JavaSE复习


1.对象的多态(核心,重点)

1.对象编译类型和运行类型可以不一致,可以让父类的引用指向子类的对象

1
Animal animal = new Dog();

等号左边编译类型,右边运行类型(编译就是javac的时候,运行就是真正运行的时候)

2.编译类型在定义对象时就确定了,不能改变

3.可以在形参列表直接声明父类引用,将子类对象传进去


4.向上转型:父类的引用指向子类的对象(向上转型的本质),可以调用父类的所有成员(遵守访问权限),但是不能调用子类的成员

因为在编译阶段,(声明好了),能调用哪些成员,由编译类型决定。运行结果看子类,从子类开始查找方法并调用


5.向下转型:子类类型 引用名 = (子类类型) 父类引用

1
Cat cat =(Cat) animal;

只能强转父类引用,不能强转父类对象(因为对象已经在内存创建好了)

父类引用必需指向当前目标类型的对象(也就是说必须满足下面条件为前提,才能向上面那样写)

1
Animal animal = new Dog();

向下转型后就可以调用子类类型中的所有成员


6.属性重写问题:属性没有重写一说,属性就看编译类型就行

1
int a = 1;

脑筋急转弯

1
2
3
4
5
6
7
8
9
10
11
Base base = new Sub();
System.out.println(base.count);

class Base { //父类
int count = 10;
//属性 }

class Sub extends Base {//子类
int count = 20;
//属性 }

结果为10,因为属性看编译类型

7.instanceOf 用来判断对象的运行类型是不是某某类型或者是不是某某类型的子类类型


2.动态绑定机制 p315(非常重要)

image-20221015170815917

  1. a的编译类型是A,运行类型是B,当将B类的sum()方法注释掉时,会自动找其父类A的sum()方法。

  2. 但是父类sum()方法中有调用一个getI方法,这时动态绑定(运用第一条机制,对象a和运行类型B绑定),会调用子类的getI方法。

  3. 但是子类(B类)的getI方法return i是return的B类定义的i(20),运用第二条机制,属性没有动态绑定,哪里声明,哪里使用。


3.断点调试

image-20221015193625682

  1. 断点调试是在程序运行的状态下

    • F7(跳入) F8(跳过)

    • shift+F8(跳出) F9(resume,执行到下一个断点)

    • F7:跳入方法内

    • F8: 逐行执行代码

    • shift+F8: 跳出方法

  2. 图片从左到右:逐行执行(F8),进入到方法体内(F7),强制进入方法体内(alt+shift+F7),跳出方法(shift+F8)

  3. 左边从上到下:resume,执行到下一个断点(F9),stop

  4. 追源代码:有些jdk源码进不去,可以强制进去。

  5. 支持动态下断点:在程序运行过程中还可以下断点。


4.Java反射机制

  1. 需求引出反射:根据properties配置文件的指定信息,创建对象并调用方法。

    • 首先要io流接收到类的路径,第一步,加载类,返回Class类型的对象cls

      1
      Class cls = Class.forName(classfullpath);
    • 通过 cls 获取你加载得到的类的对象实例:此时的o的运行类型是cat

      1
      Object o = cls.newInstance();
    • 通过cls获取你加载得到的类的 方法名字 ,来找到对应的方法对象(在反射机制中,方法也可以看作对象)(io流获得的方法名传入)。

      1
      Method method1 = cls.getMethod(methodName);
    • 通过method1调用方法:即通过方法的对象来实现调用方法。

    • 传统方法对象.方法(),反射机制方法.invoke(对象)

      1
      method1.invoke(o);
  2. 总结:框架=反射+注解+设计模式,在不修改源码的情况下控制程序,符合设计模式的ocp原则(开闭原则:不修改源码,扩展功能)

  3. 反射原理图:

  • 反射原理:执行期间借助于Reflection API取得任何类的内部信息(成员变量,构造器,成员方法),并能操作对象的属性和方法。

  • 在加载类过后,堆中就会产生相应的Class类型的对象(一个类只有一个class对象),这个对象包含了类的完整结构信息。通过这个对象看到类的结构,就像镜子一样,故得名:反射

  • 原理图:image-20221104110317798

  • java反射的功能:

    1.在运行时判断任意一个对象所属的类
    2.在运行时构造任意一个类的对象
    3.在运行时得到任意一个类所具有的成员变量和方法
    4.在运行时调用任意一个对象的成员变量和方法
    5.生成动态代理

  • 反射相关的类:
    1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
    2.java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
    3.java.lang.reflect.Field:代表类的成员变量(字段),Fild对象代表某个类的成员变量
    4.java.lang.reflect.Constructor:代表类的构造方法,.Constructor代表某个类的构造方法
    这些类在java.lang.reflection

  • cls.getConstructor(String.class)//这里老师传入的String.classs,就是String类的Class对象,可以获得含参构造器

  1. 反射调用优化:
    • 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机
      制,框架技术就失去底层支撑。
    • 缺点:使用反射基本是解释执行,对执行速度有影响。
    • 优化,method,field,constructor对象都有setAccessible()方法。这个方法的作用是启动和禁用访问安全检查的开关:参数为true,反射的对象在使用时取消访问检查,提高反射效率。参数值为false表示反射的对象执行访问检查。
  2. Class类分析:
    • Class也是类,继承了了Obejct类。
    • Class类不是new出来的,而是系统ClassLoder类的loadClass方法创建出来的。无论是new还是反射底层都会调用这一方法。
    • 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次。
    • 每个对象实例都会记得自己由哪个Class实例所生成。
    • 通过Class类可以完整的得到一个类的结构,通过一系列api
    • 常用方法:image-20221105101132831
    • Class对象是存放在堆的
    • 类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限)
  3. 获取Class对象的六种方式:
    • 代码阶段:主要是通过Class.forname(全类名)获取。前提:已知一个类的全类名,且该类在类路径下。场景:多用于配置文件,读取类的全路径,加载类。
    • 类加载阶段:通过类.class。该方式安全可靠,程序性能最高。场景:多用于参数传递,比如通过反射得到对应构造器对象。
    • 运行阶段:对象.getClass()
    • 还可以类加载器获取0717