java对象篇
一、面向对象编程(OOP)
- 面向对象和面向过程
-
面向过程思想:线性思维
-
步骤清晰简单,顺序执行
-
适合处理一些较为简单的问题
-
-
面向对象思想
-
物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独的思考。最后才对某个分类下的细节进行面向过程的思索。
-
合适处理复杂的问题,适合处理需要多人协作的问题
-
-
对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
- 面向对象:
- 本质:以类的方式组织代码,以对象形式的组织(封装)数据
- 抽象:将一个对象的共同特性抽取出来
- 三大特性:
- 封装
- 继承
- 多态
- 从认识的角度来考虑是先有对象后有类。对象是具体的事物。类是抽象的,是对对象的抽象。
- 从代码运行的角度考虑是先有类后有对象。类是对象的模板。
二、回顾方法的定义和调用
1.方法的定义
-
修饰符
-
返回类型
-
break return的区别:
break语句的使用场合主要是switch语句和循环结构。在循环结构中使用break语句,如果执行了break语句,那么就退出循环,接着执行循环结构下面的第一条语句。如果在多重嵌套循环中使用break语句,当执行break语句的时候,退出的是它所在的循环结构,对外层循环没有任何影响。如果循环结构里有switch语句,并且在switch语句中使用了break语句,当执行switch语句中的break语句时,仅退出switch语句,不会退出外面的循环结构。
continue语句是这5种结束循环的方式中最特殊的,因为它并没有真的退出循环,而是只结束本次循环体的执行,所以在使用continue的时候要注意这一点。
如果在程序中遇到return语句,那么代码就退出该函数的执行,返回到函数的调用处,如果是main()函数,那么结束整个程序的运行。
-
方法名
-
参数列表
-
异常抛出
2.方法的调用
- 静态方法:static,通过类名可直接调用
- 非静态方法:需要实例化后调用
非静态方法可以调用静态方法和非静态方法
public void Method1(){
Method2();
Method3();
}
public static void Method2(){}
public void Method3(){}
静态方法只能调用静态方法
public static void Method1(){
Method2();
//只有实例化后才可以调用非静态方法
//Method3();报错
}
public static void Method2(){}
public void Method3(){}
- 形参和实参
- 值传递和引用传递
//值传递,不会改变原有的数据
public static void main(String[] args) {
int a=1;
System.out.println(a);
Change(a);
System.out.println(a);
}
public static void Change(int a){
a=100;
}
//两次输出都是1
//引用传递
public class MethodDemo02 {
public static void main(String[] args) {
Person person =new Person();
System.out.println(person.name);//默认为空,输出null
person.name="韩小小";
System.out.println(person.name);//输出韩小小
}
}
//一个类中只能有一个public
class Person{
String name;
}
- this关键字
- 递归
三、对象的创建
-
类和对象的关系
- 类是一种抽象的数据类型,它是对某一类事物整体的描述或定义,但是并不代表一个具体的事物
- 对象是抽象概念的具体实例
-
创建与初使化对象
-
使用new关键字
-
使用new关键字的时候,除了分配内存空间外,还会给创建好的对象进行默认初使化以及对类中的构造器的调用
-
类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的,并且构造器有以下两个特点
- 必须和类的名字相同
- 必须没有返回值,也不能写void
alt+ins快捷插入构造方法 构造方法的作用是 1.当用new初使化对象时会调用 2.可以用来初使化类中的字段 构造方法如果显式的定义了,则默认就不生成不带参数的构造方法
-
四、创建对象内存分析
当程序运行时,会首先在堆中的方法区内加载类的信息,如方法、常量(放在常量池中),同时将在静态方法区中加载静态方法和静态变量;然后会将main方法的引用压入到栈的最底层,当对象创建时,将对象的引用依次压入栈中,栈中的引用指向椎中的内存,对象成员赋值时,读取方法区的信息进行赋值;可直接调用静态方法区的方法
五、封装
- 该露的露,该藏的藏
- 程序设计追求“高内聚,低耦合”。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
- 低耦合:仅暴露少量的方法给外部使用,就是说两个相关的模块尽可以能把依赖的部分降低到最小,不要让两个系统产生强依赖
- 程序设计追求“高内聚,低耦合”。
- 封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应该操作接口来访问,这称为信息隐藏
- 记住:属性私有,get/set
- 封装的好处
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护性增强
六、继承
- 继承的本质是对某一批类的抽象,从而现实对现实世界更好的建模
- 用extends关键字,意思是“扩展”,子类是父类的扩展
- java只有单继承
- 继承是类和类之间的一种关系,除此之外,类与类之间还有依赖、组合、聚合等关系
- 继承是一种is a的关系
七、super和this
super:
- 代指父类对象,可通过super.来调用父类中的成员
- 当new一个子类对象时,默认会去调用父类的构造方法,其写法上省略了一个super();
- super()在构造函数中是调用父类的构造器,必须要匹配起来,若重写了带参数的构造器,则默认的不带参数的构造器会被删除
- super或this调用构造方法必须放在构造方法的第一行
this:
- 代指当前类的对象,可通过this.来调用当前对象的成员
//父类
public class Person {
public Person(int age) {
this.age = age;
}
int age=50;//修饰符为默认的,不用写
public void Test1(){
System.out.println("this is father calss");
}
}
public class Teacher extends Person{
public Teacher() {
super(5);//调用父类的构造器,并传给父类参数
this.age=10;
}
public int age=10;
public void Test(int age){
System.out.println(this.age);//输出10,当前对象的age
System.out.println(age);//输出5,传递过来的参数,若没有传参,则为当前对象
System.out.println(super.age);//输出0,父类的age,但如果父类成员的修饰符为private,则无法调用
Test1();//输出子类的Test1方法
this.Test1();//输出子类的Test1方法
super.Test1();//输出父类的Test1方法
}
}
public class Application
{
public static void main(String[] args) {
Teacher teacher=new Teacher();
teacher.Test(5);
}
}
八、方法重写
- 重写是针对类的方法的,若父类方法和子类方法全是static修饰,则对象调用的方法和声明的对象类型有关,static方法和重写没什么关系,因为在类加载时static方法就已经被加载到静态方法区了
public class A {
public static void Test(){
System.out.println("A-->Test");
}
}
public class B extends A{
public static void Test(){
System.out.println("B-->Test");
}
}
public static void main(String[] args) {
A b = new B();
b.Test();//调用A类的方法
B b1 = new B();
b1.Test();//调用B类的方法
}
- 若存在继承关系,子类会重写父类的方法,如下,在new对象时,将父类的引用指向了子类,可以用上面的原理图来理解,子类重写了父类的方法,因此调用父类的方法,就是调用子类重写后的方法
- 修饰符的范围:子类的范围可以扩大,但不可以缩小,就是说不能比父类的访问级别低 ,默认的修饰符是空,含义是指在同一个包下的
- 异常的抛出可以被缩小,不能被放大
- 当父类的功能子类不需要或不能满足子类时,可进行方法的重写
九、多态(父类引用指向子类对象)
-
动态编译:类型:可扩展性 ,只有在程序运行的后才能确定对象的类型
-
即同一方法可以根据发送对象的不同而采用多种不同的行为方式
-
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多
-
多态存在的条件
- 有继承关系
- 子类重写父类的方法
- 父类引用指向子类对象Father f1=new Son();
-
有三种方法不能重写
- static静态方法,属于类,不属于实例
- final:常量,存在于常量池中
- private方法
-
注意:多态是方法的多态,属性是没有多态性的
public class Person {
public void Run(){
System.out.println("Person run");
}
}
public class Student extends Person{
@Override
public void Run() {
System.out.println("Student run");
}
public void Eat(){
System.out.println("Student eat");
}
}
public static void main(String[] args) {
//一个对象的实际类型是确定的
// new Student()
// new Person()
//可以指向的引用是不确定的,父类可以指向子类的引用
Student s1 = new Student();//Student能调用的对象都是自己的或继承父类的
Person s2 = new Student();//Person类指向子类,但不能调用子类独有的方法
Object s3=new Student();
//如果不重写子类的方法,则调用Run全都会调用父类的方法,因为子类继承了父类的方法
//如果子类重写了父类的方法,则调用Run都会输出子类重写后的方法,子类已经重写了父类的方法
s1.Run();
s2.Run();
//对于子类中父类没有方法,父类对象无权调用,除非使用强制类型转换
s1.Eat();
((Student)s2).Eat();
}
- 总结:
- 所谓多态就是子类重写了父类的方法,当把父类对象指向子类时,父类对象会表现出子类对象的特征,也就是调用子类重写后的方法,从而实现一个同一方法表现出不同的行为(父类对象直接调用父类本身的方法,以及父类对象指向子类对象调用子类重写后的方法)。
- 父类对象不能调用子类独有的方法
- 要实现多态必须要有继承关系
十、instanceof和类型转换
instanceof:
-
instanceof的作用是判断一个对象是什么类型,以及子类和其他类是否存在父子关系,存在返回true,否则为false
-
System.out.println(X instanceof Y);能否通过编译,取决于X和Y类型有没有父子关系
-
System.out.println(X instanceof Y);是否为true,则取决于X所指向的实际类型是不是Y类型或者其子类型
-
简单来说intanceof是用来判断一个对象是不是一种类型或者其子类型,是返回true,否则为false
-
instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:
boolean result = obj instanceof Class
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。
Object obj=new Student(); System.out.println(obj instanceof Student); System.out.println(obj instanceof Person); System.out.println(obj instanceof Object);//子类的实例化需要先调用父类的构造方法,父类是包含于子类的,因此在判断时,返回true System.out.println(obj instanceof Teacher); System.out.println(obj instanceof String); System.out.println("++++++++++++++++++++++++++"); Person Per=new Student(); System.out.println(Per instanceof Student); System.out.println(Per instanceof Person); System.out.println(Per instanceof Object);//子类的实例化需要先调用父类的构造方法,父类是包含于子类的 System.out.println(Per instanceof Teacher); //System.out.println(Per instanceof String);//编译不通过 System.out.println("++++++++++++++++++++++++++"); Student stu=new Student(); System.out.println(stu instanceof Student); System.out.println(stu instanceof Person); System.out.println(stu instanceof Object);//子类的实例化需要先调用父类的构造方法,父类是包含于子类的 //system.out.println(stu instanceof Teacher);//编译不通过 //System.out.println(Per instanceof String);//编译不通过 //student\person\object类均输出true,其他为false
引用类型类型转换:
- 子类转父类可以直接进行转换,可能丢失方法,子类的独有方法不能被父类调用
- 父类转子类需要进行强制转换
- 优点:方便方法的调用,减少代码重复,使代码更简洁
//Student类是Person类的子类,Eat方法为Student类独有
//父类引用指向子类对象
//子类转父类可以直接转,但会损耗一些方法(子类的方法父类无法调用)
//父类转子类,需要强制类型转换
Student stu=new Student();
stu.Eat();
Person stu1 = stu;
//stu1.Eat();无法调用
((Student)stu1).Eat();
十一、静态static
static
对象可以调用静态属性,也可以通过类名调用,推荐使用类名调用,静态属性被类中的实例所共享。
静态方法不能调用动态方法,因为静态方法在类加载的时候加载的,而动态方法是在创建对象的时候加载的。
public class Student {
private static int age;//静态属性
private int score;//非静态属性
public void run(){
Student.go();
go();
}
public static void go(){
//run(),静态方法不能调用动态方法,因为动态方法是属于对象的,只有在对象创建后并通过对象来调用
}
public static void main(String[] args) {
Student st1=new Student();
System.out.println(st1.age);
System.out.println(st1.score);
System.out.println(Student.age);//推荐,静态成员能被类中的实例所共享
go();
Student.go();
new Student().run();
}
}
代码块和静态代码块
-
在创建对象时,执行构造方法之前还会执行匿名代码块以及静态代码块,静态代码块在程序中只能执行一次
-
执行顺序 :静态代码块->匿名代码块->构造方法
public class Person {
static {
//代码块
System.out.println("静态代码块");//Java静态代码块中的代码会在类加载JVM时运行,且只被执行一次
}
{
//代码块
System.out.println("匿名代码块");
}
public Person() {
System.out.println("构造方法");
}
public static void main(String[] args) {
new Person();//静态代码块先执行,然后是匿名代码块,最后是构造方法
System.out.println("=========================");
new Person();//静态代码块只执行一次,这里只输出匿名代码块和构造方法
}
}
静态导入包
静态导入包,可直接调用包中的静态方法
//静态导入包,可直接调用包中的静态方法
import static java.lang.Math.random;
import java.lang.Math;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());
System.out.println(random());
}
}
十二、抽象类
- 抽象类要用abstract来实现
- 抽象类中的抽象方法要加abstract
- 不能创建抽象类的对象,只能用子类来实现
- 单继承
- 抽象类就是一种约束
- 抽象类中也有构造方法
十三、接口
- 对比:
- 普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有
- 接口:只有规范
- 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是...则必须能...”的思想。
- 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
- OO的精髓,是对对象的抽象,接口最能体现这一点。
- 我们讨论设计模式都只针对具备了抽象能力的语言,就是因为设计模式所研究的,实际上就是如何合理的去抽象。
- 声明接口的关键字是interface
- 接口没有构造方法
- 接口中可以有属性,为常量,默认属性省略public static final
- 接口中方法默认为public abstract修饰,一般省略
public interface InterTest {
void test();
int test2();
}
public interface UserService {
int AGE=99;// 默认属性省略public static final,常量
public static final int AGE2=98;
void add();
public abstract void del();
void up();
void query();
}
public class UserDemoImpl implements InterTest, UserService {
@Override
public void test() {
}
@Override
public int test2() {
return 0;
}
@Override
public void add() {
}
@Override
public void del() {
}
@Override
public void up() {
}
@Override
public void query() {
}
}
十四、内部类
- 成员内部类
public class NumInnerClass {
private int ID=66;
public void Test(){
System.out.println("this is outter class method");
}
//注意public关键字
public class InnerClass{
public void Test(){
System.out.println("this is inner class Test");
}
public void Test1(){
System.out.println("this is inner class Test1");
}
public void Test3(){
System.out.println(ID);//可调用外部类的private成员
}
}
}
public class Application {
public static void main(String[] args) {
NumInnerClass numInnerClass=new NumInnerClass();
numInnerClass.Test();
NumInnerClass.InnerClass ic = numInnerClass.new InnerClass();//要通过对象.来进行实例化
ic.Test();
ic.Test1();
ic.Test3();
}
}
- 静态内部类(static)
public class NumInnerClass {
private static int ID=66;
public void Test(){
System.out.println("this is outter class method");
}
public static class InnerClass{
public static void Test1(){
System.out.println("this is inner class Test1");
}
public static void Test3(){
System.out.println(NumInnerClass.ID);//不能调用非静态成员
}
}
}
public class Application {
public static void main(String[] args) {
NumInnerClass numInnerClass=new NumInnerClass();
numInnerClass.Test();
NumInnerClass.InnerClass.Test3();
NumInnerClass.InnerClass.Test1();
}
}
- 局部内部类
public class Test {
public void method01(){
//局部内部类
class A {
int age=1;
}
A a = new A();
System.out.println(a.age);
}
}
public class Application {
public static void main(String[] args) {
Test test = new Test();
test.method01();
}
}
- 匿名内部类
public class Test02 {
public static void main(String[] args) {
new Apple().eat();
Luzhenguo luzhenguo = new Luzhenguo() {
@Override
public void test05() {
}
};
}
}
class Apple{
public void eat(){}
}
interface Luzhenguo{
void test05();
}
十五、异常机制Exception
- 异常指程序中出现的不期而至的各种状况,如文件找不到、网络连接失败
- 异常发生在程序运动期间,它影响了正常的程序执行
异常的简单分类:
1.检查性异常: 不处理编译不能通过,如打开一个文件不存在
2.非检查性异常:不处理编译可以通过,如果有抛出直接抛到控制台,如空指针
public static void main(String[] args) {
System.out.println(11/0);//ArithmeticException
}
3.运行时异常: 就是非检查性异常
4.非运行时异常: 就是检查性异常
5.错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略,如栈溢出
public class ExceptionDemo {
public static void main(String[] args) {
new ExceptionDemo().a();//Exception in thread "main" java.lang.StackOverflowError
}
public void a(){
b();
}
private void b() {
a();
}
}
java的异常体系结构
Error
- Error类对象由java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
- java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,java虚拟机(JVM)一般会选择线程终止。
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
Exception
十六、异常处理机制
throw
package Demo06;
public class Test {
public static void main(String[] args) {
//ctrl+alt+T
try {//需要捕获的内容
int a=11,b=0;
if (b==0){
throw new ArithmeticException();//throw关键字可直接抛出异常
}
System.out.println(a/b);//此处程序不会走
} catch (Exception e) {
//对抛出异常的处理,如果要捕获多个异常,参数顺序应该是从小到大,否则编译直接报错
System.out.println("111");
}catch (Error error){
System.out.println("222");
}catch(Throwable throwable){
System.out.println("333");
} finally {//善后工作,始终会被执行,一般用于资源的释放
System.out.println("f");
}
}
}
throws:
throw是抛出异常,throws是往上抛异常
package Demo06;
public class Test {
public static void main(String[] args) {
//ctrl+alt+T
//在Main方法中进行捕获并处理
try {
new Test().test(11,0);
} catch (ArithmeticException e) {
System.out.println("111");
} finally {
}
}
//异常如果处理不了,可以抛给下一个调用者
public void test (int a,int b) throws ArithmeticException{
if (b==0){
throw new ArithmeticException();//throw关键字可直接抛出异常
}
System.out.println(a/b);//此处程序不会走
}
}
自定义异常
public class MyException extends Exception{
//判断是否大于10
private int a;//定义一个int类型的数用来保存传入的值
public MyException(int a) {//构造方法给a赋值
this.a=a;
}
//重写tostring
@Override
public String toString() {
return "MyException{" +
"a=" + a +
'}';
}
}
public class Application {
public static void main(String[] args) {
try {
test(11);
} catch (MyException e) {
System.out.println("大于11"+e);
}
}
//可抛出也可直接捕获
static void test(int a) throws MyException {
if (a>10){
throw new MyException(a);
}
System.out.println("ok");
}
}
本文来自博客园,作者:一只快乐的小67,转载请注明原文链接:https://www.cnblogs.com/sp520/p/15574431.html