一:类的初始化过程:
1.先加载类级别的成员(静态成员变量的方法 以及 静态初始化块,这两个打印的顺序依据出现的先后顺序)
2.再加载对象级别的成员(实例初始化块、普通成员变量的方法,打印的顺序依据出现的先后顺序)
3.构造函数
具体例子:
public class ObjectInitTest { public ObjectInitTest() { System.out.println("这是构造函数alta+Insert快捷键:ObjectInitTest()"); } //静态初始化块 static{ b=10; System.out.println("静态初始化块"); } //实例初始化块 对实例成员变量(依赖于对象) { System.out.println("instance init block"); } private int a=method1();//普通的成员变量,对象级别的 private static int b=method2();//静态的成员是共享的,类级别的 private int method1() { System.out.println("对象级别的method 1"); return 1; } private static int method2() { System.out.println("静态的,类级别的method 2"); return 2; } public static void main(String[] args) { /** * new ObjectInitTest() * 对象的产生过程 * 1. JVM会在ObjectInitTest.class文件 * 2. 先加载类级别的成员(静态成员变量的方法 以及 静态初始化块,这两个打印的顺序依据出现的先后顺序) * 3. 再加载对象级别的成员(实例初始化块、普通成员变量的方法,打印的顺序依据出现的先后顺序) * 4.构造函数 */ ObjectInitTest o=new ObjectInitTest(); } }
继承类同理: 静态>普通 基类>继承类
先打印基类的静态方法以及静态初始化块(根据出现的先后顺序),再打印子类的静态方法及静态初始化块(先后顺序)。
再打印基类普通的方法以及普通实例化块(先后),最后打印基类的构造函数;再打印子类的普通方法及普通实例化块(先后),最后打印子类的构造函数。
public class ObjectInitTest2 extends ObjectInitTest { private static int c=method3(); public static int method3(){ System.out.println("这是继承类的静态方法"); return 3; } static{ System.out.println("继承类的静态初始化块"); } private int d=method4(); public int method4(){ System.out.println("这是继承类的普通的成员方法"); return 4; } { System.out.println("继承类的普通实例化块"); } public ObjectInitTest2(){ System.out.println("继承类的构造方法"); } public static void main(String[] args) { ObjectInitTest2 o2=new ObjectInitTest2(); } }
二:super关键字
this关键字的两个用法:
* 1.在构造函数中调用如 this(10),调用带int参数的其它的构造函数
* 2.在成员方法里面访问其它成员,前面可以添加this.
*
* super关键字的三个用法:
* 1.在派生类的构造函数中,调用super(10),调用基类的带int参数的构造函数
* 2.super.func() 在派生类中,调用从基类继承来的func方法
* 3.super.a 在派生类中,调用从基类继承来的名字叫a的成员变量
*
* this和super关键字都和对象有关,所以在static方法中不能使用这两个关键字
实例:
/** * 描述: * OOP(面向对象编程)中两个类常有的关系有两种: * 组合关系:满足a part of... 一部分 一个类定义的对象称为另一个类的成员变量 has a..的关系 * A类是B类的一部分,A和B就设计成组合关系,设计如下 * class A{} * class B{ * A a; // B组合了A对象 A是B的成员变量 * public B{ * this.a = new A(): * } * } * * 继承关系:满足 a kind of... 一种的关系 用extends继承 is a..的关系 * A是一个已经定义的类,B是A的一种,那么设计成继承关系,如下: * class A{} * class B extends A { * * } * * OOP语言的四大特征是什么? * 抽象 封装 继承 多态 * 三大特征是什么? * 封装 继承 多态 * 封装/隐藏 : 通过类的访问限定符实现的 private public * * * 继承的意义之一:代码的复用 * * 两个类什么时候设计成继承? * 派生类对象的初始化过程? * 基类的成员在派生类中如何访问? * 在派生类中如何调用基类的成员? * * this关键字的两个用法: * 1.在构造函数中调用如 this(10),调用带int参数的其它的构造函数 * 2.在成员方法里面访问其它成员,前面可以添加this. * * super关键字的三个用法: * 1.在派生类的构造函数中,调用super(10),调用基类的带int参数的构造函数 * 2.super.func() 在派生类中,调用从基类继承来的func方法 * 3.super.a 在派生类中,调用从基类继承来的名字叫a的成员变量 * * this和super关键字都和对象有关,所以在static方法中不能使用这两个关键字 * * private和protected的区别? * 1.它们两个修饰的成员,在类的外部都不能访问 * 2.基类的private成员,在派生类中无法访问;基类的protected成员,在派生类中可以访问 * @Author hui * @Date 2019/10/15 */ public class DeriveTest { public static void main(String[] args) { // A a=new A(); B b=new B(6); b.show(); } } class A{ protected int a; static { System.out.println("A的静态块"); } { System.out.println("A的实例化块"); } public A(){ System.out.println("A的无参数构造函数"); this.a=0; } public A(int a){ System.out.println("A的int参数的构造方法"); this.a=a; } public void show(){ System.out.println("A.show is a:"+a); } } /** * 派生类B有两部分 * 1.从基类继承来的成员 * 2.自己定义的成员 * * super()和this()都必须写在第一行 */ class B extends A{ private int a; private int b; public B(int data){ super(4);//将4传给基类的a this.a=data;//给B的a进行初始化赋 System.out.println("B的带参数的构造函数int(data)"); } static { System.out.println("派生类B的静态块"); } { System.out.println("B的实例化方法"); } //重写父类的方法,打印基类与自己的a变量 public void show(){ System.out.println("A.show a is:"+super.a); System.out.println("B.show is a:"+a); } //调用基类的方法super关键字 void testShow2(){ super.show(); } }
三:函数的动态绑定
实例:
/** * 函数的静态绑定和动态绑定是什么? * 绑定(函数调用) * invokestatic指令就是在以静态绑定的方法,调用函数 * invokevirtual指令就是在以动态绑定的方法,调用函数 * * static方法都是静态绑定调用 * 实例方法都是动态绑定调用 * * 静态绑定,指的是编译时期的绑定,编译阶段,这个方法的调用就是确定好的,永不不会再改变 * * 动态绑定,指的是运行时期的绑定,就是在编译阶段,此处调用哪个函数,是不确定的, * * final的应用场景有三个: * 1.final int data = 10; 可以用来定义常量 * 2.final可以修饰类称作密封类,不能再被继承 * 3.final可以修饰类的实例方法,称作密封方法, * 表示该方法不能再派生类中重写(覆盖) */ class Base{ protected int a; private String str; private Integer data; public Base(int val){ //构造函数 System.out.println("Base(val)"); this.a = val; } public static void show(){ //静态方法 System.out.println("static Base.show"); } public void func(){ //实例化方法 System.out.println("instance Base.func"); } public void func(int data){ //方法的重载,在同一个类里进行 System.out.println("instance Base.func data"); } } /** * 继承结构中,基类和派生类的方法通常有两种关系:重载和重写 * 重载:在一个类作用域中,函数名相同,参数列表不同 * 重写:在基类和派生类中,出现返回值相同,函数名相同,参数列表也相同的实例方法 * 重写指的是派生类方法表中,派生类提供的重写方法,把基类相应的方法的地址给重写了(覆盖了) */ class E extends Base{ //E的构造函数调用父类的构造函数 public E(int val) { super(val); System.out.println("派生类E的构造函数"); } //派生类重写基类的方法 public static void show(){ System.out.println("static E.show"); } // 构成重写(覆盖)的关系 public void func(){ System.out.println("instance E.func"); } } /* *基类引用,可以引用派生类对象 *派生类引用,不可以引用基类对象 * *把基类和派生类的继承结构,也经常称作从上到下的继承结构, *继承结构中的类型,只支持从下到上的转换,不支持从上到下的转换 */ public class FunctionBond { public static void main(String[] args) { E e = new E(20); // invokespecial 构造函数,调用派生类E的构造函数 E.show(); // invokestatic 静态绑定 e.func(); // invokevirtual 实例方法 Base b = new E(20); //动态绑定,调用派生类E的构造函数 Base.show(); // Base.show b.func(); // 调用派生类的方法 } }
反汇编指令:javap -c 类名.class
实际的调用分析:
注:基类可以引用派生类对象,派生类不可以引用基类对象
(举例:你此时需要一个人,来一个教授可以满足;但是当你需要一个教授,随便来一个人则不能满足需求)