美文网首页程序员
Java学习笔记--构造器的调用顺序

Java学习笔记--构造器的调用顺序

作者: Luckily_Liu | 来源:发表于2017-10-06 19:07 被阅读25次

前言

工作之余回头巩固一下Java知识,只有基础牢固了才能走的更远。

基类的构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接, 以使每个基类的构造器都能得到调用。导出类只能访问自己的成员,访问不了基类中private的成员,只有基类的构造器有权限对自己的元素进行初始化。因此,必须令所有的构造器都得到调用,否则就不可能正确的构造完整的对象。

示例:

class Meal{
    Meal(){
        System.out.println("Meal()");
    }
}

class Chesses{
    Chesses(){
        System.out.println("Chesses()");
    }
}

class Bread{
    Bread(){
        System.out.println("Bread()");
    }
}

class Lettuce{
    Lettuce(){
        System.out.println("Lettuce()");
    }
}

class Lunch extends Meal{
    Lunch() {
        System.out.println("Lunch()");
    }
}

class ProtableLunch extends Lunch{
    ProtableLunch() {
        System.out.println("ProtableLunch");
    }
}

public class Sandwich extends ProtableLunch{

    private Bread bread = new Bread();
    private Chesses chess = new Chesses();
    private Lettuce lettuce = new Lettuce();
    public Sandwich() {
        System.out.println("Sandwich()");
    }
    
    public static void main(String[] args) {
        Sandwich sandwich = new Sandwich();
    }

}
---------------------------------------------------
Output:

Meal()
Lunch()
ProtableLunch
Bread()
Chesses()
Lettuce()
Sandwich

由输出结果可见,构造器的大致初始化顺序如下:

  • 1)调用基类构造器。这个步骤会不断地反复递归下去,首先是构造这种层次结构的根,然后是下一层的导出类,等等,知道最底层的导出类。
  • 2) 按照声明顺序调用成员的初始化方法。
  • 3)调用导出类构造器的主体。

按照这样的规则就能保证所有的基类成员以及当前对象的成员对象都得到了初始化。但是有一种特殊情况。

示例:

class Glyph{
    
    void draw(){
        System.out.println("Glyph.Draw()");
    }
    
    Glyph(){
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
    
}

class RoundGlyph extends Glyph{
    private int radius = 1;
    RoundGlyph(int i){
        radius = i;
        System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
    }
    
    @Override
    void draw() {
        System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
}

public class PloyConstructors {

    public static void main(String[] args) {
        new RoundGlyph(5);
    }

}

-------------------------------------------------------
Output:

Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5

在输出结果当中radius的输出结果是0,并不是默认的初始值1。所以上面所说的初始化顺序并不完整。

构造器的实际初始化顺序如下:

  • 1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零。
  • 2)如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用),由于步骤2的缘故,我么此时会发现radius的值为0。
  • 3)按照声明顺序调用成员的初始化方法。
  • 4)调用导出类构造器的主体。

因为我们在Glyph的构造器中调用draw()方法的时候,RoundGlyph的构造器还没有得到调用,所以他的存储空间此时是初始化为二进制0的,所以radius的输出结果是0。这样的错误编译器不会报错,我们也很难发现。编写构造器时有一条有效的准则:“用尽可能简单的方法使对象进入正常状态;如果可以的话,尽量避免调用其他方法。”在构造器当中唯一能够安全调用的那些方法就是基类当中的final方法(也适用于private方法,他们自动属于final方法)。这些方法不会被覆盖,因此不会出现上面的问题。

原文地址:http://blog.csdn.net/Liuhe_5656/article/details/78166486

相关文章

  • Java学习笔记--构造器的调用顺序

    前言 基类的构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接, 以使每个基类的构造器都能得到调用...

  • Java类与构造器的执行顺序与注意事项

    在Java中尽量不要在构造器里调用可能被重载的虚方法。 因为构造器的初始化顺序大概是 父类静态块---->子类静态...

  • JAVA & .NET创建对象构造函数调用顺序

    JAVA & .NET创建对象构造函数调用顺序 JAVA 定义Person类 定义Chinese类 创建Chine...

  • 10.29

    Java 中的构造器链是什么?当你从一个构造器中调用另一个构造器,就是Java 中的构造器链。这种情况只在重载了类...

  • C++中对象构造顺序

    单个对象的构造与析构 单个对象创建时构造函数的调用顺序1、调用父类的构造过程2、调用成员变量的构造函数(调用顺序与...

  • Java基础知识备忘

    对象在创建的时候会初始化,初始化时Java会调用构造器,若没有自定义构造器则会调用默认的构造器,若没有数据成员赋予...

  • 为什么不要在构造函数做太多事情

    java构造器调用的层次结构带来了一个困境。如果在构造器中调用了正在构造的对象的动态绑定方法,会发生什么呢?在普通...

  • Java实例初始化的顺序

    Java静态变量、inline初始化的实例变量,显示与隐式调用构造器的执行顺序 所有依赖路径的类(包括父类与子类)...

  • JVM06 Java中对象的内存是如何布局的?

    Java中创建对象的方式 new -通过调用构造器来初始化实例字段反射-通过调用构造器来初始化实例字段Object...

  • 类的构造器的调用顺序

    规则如下:对于一个复杂的对象,构建器的调用遵照下面的顺序:(1) 调用父类构建器。这个步骤会不断重复下去,首先得到...

网友评论

    本文标题:Java学习笔记--构造器的调用顺序

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