整理:对象实例化

对象实例化方式

  1. 使用new关键字;执行构造函数;
  2. 通过反射机制;调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法;
  3. 执行构造函数;调用对象的clone()方法;未执行构造函数;
  4. 通过反序列化;未执行构造函数。

对象实例化过程

    创建对象时,先判断是否已经初始化;若尚未初始化,则先进行类加载过程;而后调用实例构造器()方法,进行对象初始化过程。一个类的初始化过程在此类对象初始化过程之前触发,即()方法在()方法之前执行。

    对象实例化,主要关注以下两个方面:

      实例构造器()方法执行时,当前类实例变量、语句块、构造方法的执行顺序;

      创建子类对象时,当前类及其父类实例构造器()方法的执行顺序。

    实例变量、语句块、构造方法的执行顺序

public class Test {
    // 实例变量: i
    int i;
    // 语句块: A
    {
        System.out.println("A_1 i: " + this.i + " ;j: " + this.j);
        i = 2;
        j = 2;
        System.out.println("A_2 i: " + this.i + " ;j: " + this.j);
    }
    // 构造方法
    public Test(int i, int j) {
        System.out.println("T_1 i: " + this.i + " ;j: " + this.j);
        this.i = i;
        this.j = j;
        System.out.println("T_2 i: " + this.i + " ;j: " + this.j);
    }
    // 语句块: B
    {
        System.out.println("B_1 i: " + this.i + " ;j: " + this.j);
        i = 3;
        j = 3;
        System.out.println("B_2 i: " + this.i + " ;j: " + this.j);
    }
    // 实例变量: j
    int j = 1; 
    public static void main(String[] args) {
        Test t = new Test(4, 4);
        System.out.println("main i: " + t.i + " ;j: " + t.j);
    }
}
输出结果:
  A_1 i: 0 ;j: 0
  A_2 i: 2 ;j: 2
  B_1 i: 2 ;j: 2
  B_2 i: 3 ;j: 3
  T_1 i: 3 ;j: 1
  T_2 i: 4 ;j: 4
  main i: 4 ;j: 4

  结果分析:

    A_1:实例变量i、j值均为0;此时两个变量尚未手动赋值,所以值都是默认零值;

    A_2:手动赋值后,实例变量i、j值被设置为2;

    B_1:跳过构造方法,执行语句块B,实例变量i、j值依旧为2;

    B_2:手动赋值后,实例变量i、j值被设置为3;

    T_1:构造方法执行,实例变量j值为1;在构造方法执行之前,先执行了语句块B下面的赋值操作,j被设置为1;

    T_2:手动赋值后,实例变量i、j值被设置为4;

    main:对象创建完毕,打印对象实例变量i、j。

  通过输出结果可以验证:

  • 实例变量在被赋值及其他操作之前,虚拟机会对其进行一个与类加载准备过程相似的实例化准备过程:在堆中为实例变量分配内存空间并设置实例变量初始值(一般情况下是数据类型的零值);
  • 实例变量的初始化赋值操作及语句块的执行顺序优先于构造方法执行;
  • 实例变量和语句块按照代码书写的顺序,由上至下依次执行;

    目标类及其父类实例构造器()方法的执行顺序

public class Test {
    public static void main(String[] args) {
        Sub sub = new Sub();  // 创建sub对象
        System.out.println("main a: " + sub.a + "; b: " + sub.b);
    }
}
class Sup {
    // 父类实例变量: a
    int a = 1;
    // 父类语句块:A
    {
        System.out.println("A_1 a: " + a);
        a = 2;
        System.out.println("A_2 a: " + a);
    }
    // 父类构造方法
    public Sup() { 
        System.out.println("sup this: " + this.getClass().getName() + "; getValue: " + this.getValue());
    }
    // 父类getValue方法
    public int getValue(){
        return a;
    }
}
class Sub extends Sup{
    // 子类实例变量: b
    int b = 1;
    // 子类语句块:B
    {
        System.out.println("B_1 b: " + b);
        b = 2;
        System.out.println("B_2 b: " + b);
    }
    // 子类构造方法
    public Sub() {
        System.out.println("sub this: " + this.getClass().getName() + "; getValue: " + this.getValue());
    }
    // 子类getValue方法
    @Override
    public int getValue() {
        return b;
    }
}
输出结果:
  A_1 a: 1
  A_2 a: 2
  sup this: com.Sub; getValue: 0
  B_1 b: 1
  B_2 b: 2
  sub this: com.Sub; getValue: 2
  main a: 2; b: 2

  结果分析:

    创建子类Sub对象,先执行其父类Sup的实例构造器。实例变量a初始赋值为1;然后执行语句块A:输出a的值,将a赋值为2,输出a的值;最后执行构造方法:输出this对应的类名及getValue方法返回值,this为Sub,方法返回0;此时父类中的this实际对应的是子类,父类实际调用的是子类的方法(子类Override的方法),此时子类尚未执行实例构造器,所以getValue返回的是默认零值;

    父类实例构造器执行后,执行子类Sub的实例构造器。实例变量b初始赋值为1;然后执行语句块B,输出b的值,将b赋值为2,输出b的值;最后执行构造方法:输出this对应的类名及getValue方法返回值,this为Sub,方法返回2;

    main方法输出a、b的值,均为2。

  通过输出结果可以验证:

  • 创建对象时,会先执行当前对象父类的实例构造器,而后才执行自身的实例构造器;
  • 执行父类实例构造器时,this是子类自身;调用方法时,如果方法被子类Override,则执行子类的方法;

本文是在阅读博客、书本及日常经验下进行的总结,比较推荐博主——书呆子Rico的文章:

https://blog.csdn.net/justloveyou_/article/details/72466416

你可能感兴趣的:(Java之路)