美文网首页
对象的创建过程-构造函数初始化(三)

对象的创建过程-构造函数初始化(三)

作者: 小尾巴1024 | 来源:发表于2019-03-26 23:06 被阅读0次

我们知道,实例变量初始化和代码块初始化问题在构造函数执行之前。
每个类至少都有一个构造函数,在编译生成字节码时,构造函数会被命名成<init>方法,参数类弄和顺序不变 。
我们知道,java在实例化类之前,必须先实例化其超类,以保存实例的完整性。事实上,这一点是在构造函数中保证的,
构造的函数的第一条语句必须是调用超类的语句或是类中定义的其他函数。如果我们没有显示地调用超类的构造函数,也没有调用类中的其它构造函数,
则编译器会自动为我们生成对超类构造函数的调用。如:

public class Student {
    public static void main(String[] args) {
        System.out.println(111);
    }
}

上面的语句没有显示地调用超类构造函数,但是我们可以查看编译后的字节码,编译器自动为我们生成了调用超类的代码,如下:


image

上面红色箭头就是调用超类Object类的构造函数。

特别地,如果我们在一个构造函数中调用另外一个构造函数,如下:

public class Student {
    private int i;
    /**
     * 在无参构造函数中调用有参构造函数
     * 对于这种情况,只允许在 Student(int i) 中调用超类的构造函数
     */
    public Student() {
        //super();    //在这里调用父类构造方法会报错,
        this(1);
    }
    public Student(int i) {
        this.i = i;
    }
    public static void main(String[] args) {
        System.out.println(111);
    }
}

总结:实例化一个类的对象的过程是一个典型的递归过程,实例化类的对象时,会先实例化该类的父类,
如果该父类还有父类,那么会一直往上递归直到Object类,先实例化Object类,再往下递归实例化,直到目标类。
实例化每个类时,遵循如下顺序,先执行实例变量初始化和实例代码块初始化,再执行构造函数初始化。
也就是説,编译器会将实例变量和实例代码块放到类的构造函数中去,并且放到超类的调用构造函数语句之后,构造函数本身代码之前 。


类加载.png

综合实例:

实例变量初始化、实例代码块初始化以及构造函数初始化

//父类
class Foo {
    int i = 1;
    Foo() {
        System.out.println(i);   //输出2 ----(1)
        int x = getValue();
        System.out.println(x);  //输出0,根据多态,调用的是子类的getValue(),而此时子类的构造函数还没被调用 ----(2)
    }
    {
        i = 2;
    }
    protected int getValue() {
        return i;
    }
}
//子类
class Bar extends Foo {
    int j = 1;
    Bar() {
        j = 2;
    }
    {
        j = 3;
    }
    @Override
    protected int getValue() {
        return j;
    }
}
public class ConstructorExample {
    public static void main(String... args) {
        Bar bar = new Bar();
        System.out.println(bar.getValue());   //输出2 ----(3)
    }
}

我们可以将Foo类的构造函数和Bar类的构造函数等价地分别变为如下形式:

 Foo() {
    i = 1;
    i = 2;
    System.out.println(i);   //输出2 ----(1)
    int x = getValue();
    System.out.println(x);  //输出0,根据多态,调用的是子类的getValue(),而此时子类的构造函数还没被调用 ----(2)
}

Bar() {
  Foo();
  j = 1;
  j = 3;
  j = 2;
}

在通过使用Bar类的构造方法new一个Bar类的实例时,首先会调用Foo类构造函数,因此(1)处输出是2,这从Foo类构造函数的等价变换中可以直接看出。
(2)处输出是0,为什么呢?因为在执行Foo的构造函数的过程中,由于Bar重载了Foo中的getValue方法,所以根据Java的多态特性可以知道,
其调用的getValue方法是被Bar重载的那个getValue方法。但由于这时Bar的构造函数还没有被执行,因此此时j的值还是默认值0,因此(2)处输出是0。
最后,在执行(3)处的代码时,由于bar对象已经创建完成,所以此时再访问j的值时,就得到了其初始化后的值2,这一点可以从Bar类构造函数的等价变换中直接看出。

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

相关文章

  • c#面向对象2--构造函数/new/this/析构函数/属性只读

    1.构造函数 类名首字母大写 构造函数:可以用来创建对象,并在构造函数中对对象进行初始化(简化初始化过程--给对象...

  • 构造函数

    构造函数是干什么用的? 在javascript中,构造函数是给对象添加属性,初始化属性作用的。 对象创建的过程 首...

  • Swift构造函数和便利构造函数

    [转]Swift构造函数和便利构造函数 构造函数基础 构造函数是一种特殊的函数,主要用来在创建对象时初始化对象,为...

  • 关键字的细节总结

    构造函数:构建创造对象时调用的函数。 作用:可以给对象进行初始化。 1.创建对象都必须要通过构造函数初始化。2.一...

  • 9.11 学习总结

    今天学了构造函数和析构函数,重载构造函数。 构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化...

  • 构造函数

    构造函数:构建创造对象时调用的函数。作用:可以给对象进行初始化。创建对象都必须要通过构造函数初始化。 一个类中如果...

  • GeekBand-C++面向对象高级编程-Lesson2

    构造函数(constructor) 控制类的对象初始化过程的函数,任务是初始化类对象的数据成员。 构造函数和类名一...

  • GeekBand笔记: C++面向对象高级编程(2)

    构造函数(constructor) 控制类的对象初始化过程的函数,任务是初始化类对象的数据成员。 构造函数和类名一...

  • 9月11日C++学习总结

    1.构造函数:构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。在对象创建时...

  • C++中的拷贝构造函数

    1.拷贝构造函数 拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对...

网友评论

      本文标题:对象的创建过程-构造函数初始化(三)

      本文链接:https://www.haomeiwen.com/subject/itcnvqtx.html