【java in think】构造器的调用顺序

class Meal
{

    public Meal()
    {
        System.out.println("Meal()--构造啦!");
    }

}

class Bread
{

    public Bread()
    {
        System.out.println("Bread()--构造啦!");
    }

}

class Cheese
{

    public Cheese()
    {
        System.out.println("Cheese()--构造啦!");
    }

}

class Lettuce
{

    public Lettuce()
    {
        System.out.println("Lettuce()--构造啦!");
    }

}

class Lunch extends Meal
{

    public Lunch()
    {
        System.out.println("Lunch()--构造啦!");
    }

}

class PortableLunch extends Lunch
{

    public PortableLunch()
    {
        System.out.println("PortableLunch()--构造啦!");
    }

}

public class Sandwich extends PortableLunch
{
    private Bread bread = new Bread();
    private Cheese cheese = new Cheese();
    private Lettuce lettuce = new Lettuce();

    public Sandwich()
    {
        System.out.println("Sandwich()--构造啦!");
    }
    public static void main(String[] args)
    {
        new Sandwich();
    }
}

输出结果如下:

Meal()--构造啦!
Lunch()--构造啦!
PortableLunch()--构造啦!
Bread()--构造啦!
Cheese()--构造啦!
Lettuce()--构造啦!
Sandwich()--构造啦!

再看一例:

class Insect
{
    private int i = 9;
    protected int j;

    public Insect()
    {
        System.out.println("i=" + i + "  j=" + j);
        j = 39;
    }

    private static int x1 = printInit("static Insect x1");

    protected static int printInit(String s)
    {
        System.out.println(s);
        return 47;
    }
}

class Beetle extends Insect
{

    private  int k = printInit("Beetle k ");

    public Beetle()
    {
        System.out.println("k=" + k + "  j=" + j);//这个j是父类的

        j = 25;
    }

    private static int x2 = printInit("static Beetle x2");
    public static void main(String[] args)
    {
        System.out.println("Beetle constructor");
        Beetle beetle = new Beetle();

     System.out.println();
     System.out.println("Beetle constructor2");
     Beetle beetle2 = new Beetle();

    }

}
//输出结果
/*
static Insect x1
static Beetle x2
Beetle constructor
i=9  j=0
Beetle k
i=47  j=39

Beetle constructor2
i=9 j=0
Beetle k
k=47 j=39

*/

在Beetle上运行java时,所发生的第一件事就是试图访问Beetle.main()(一个static方法),于是加载器开始启动并找出Beetle类的编译代码(在名为Beetle.class文件中)。在对它进行加载的过程中,编译器注意到它有一个父类(这是由extends得知),于是它继续加载(父类)。不管你是否打算产生一个该父类的对象,这都要发生(请尝试将对象创建代码注释掉,以便证明这一点)。

  如果该父类还有其自身的父类,那么第二个父类就会被加载,如此类推。接下来,根父类中的static初始化(在本例是Insect)即会被执行,然后是下一个子类,以此类推。这种方式很重要,因为子类的static初始化可能会依赖于父类成员能否被正确初始化。

  至此为止,必要的类都已经加载完毕,对象才可以创建了。首先,对象中的所有基本类型都会被设为默认值,对象引用被设为null--这是通过将对象内存设为二进制零值而一举产生的。然后,父类的构造器会被调用。在父类构造器完成之后,实例变量按其次序被初始化,最后构造器的其余部分被执行。

时间: 2024-12-12 06:26:44

【java in think】构造器的调用顺序的相关文章

java中构造器的调用顺序

在编程的过程中,我们经常会遇到多个类的继承问题,那么多个类的构造器是按照什么顺序调用的呢? 先看一段代码: 1 public class Meal { 2 public Meal() { 3 System.out.println("meal constructor() "); 4 } 5 } 6 7 public class Bread { 8 public Bread() { 9 System.out.println("bread constructor() ")

引入多态后构造器的调用顺序

前言 基类的构造器总是在导出类的构造过程中被调用,而且按照继承层次逐渐向上链接,以使每个基类的构造器都能得到调用.这样做是有意义的,因为构造器具有一项特殊任务:检查对象是否被正确的构造.导出类只能访问它自己的成员,不能访问基类中的成员(基类成员通常是private类型).只有基类的构造器才具有恰当的知识和权限来对自己的元素进行初始化.因此,必须令所有构造器都得到调用,否则就不可能正确构造完整对象.这正是编译器为什么要强制每个导出类部分都必须调用构造器的原因.在导出类的构造器主体中,如果没有明确指

Java类加载及实例化的调用顺序

标题起得略拗口,大概意思就是说在一个Java类中,域和构造方法的调用顺序. 1. 没有继承的情况 单独一个类的场景下,初始化顺序为依次为 静态数据,继承的基类的构造函数,成员变量,被调用的构造函数. 其中静态数据只会初始化一次. package com.khlin.binding.test; public class App2 { public static void main(String[] args) { Son son = new Son(); } } class Son { publi

java实例变量及方法调用顺序

public class Base { private String name="base"; public Base(){ sayHello(); } void sayHello() { System.out.println("Base hello " + name); } } class Derived extends Base { private String name="Derived"; public Derived(){ sayHel

关于Java中基类构造器的调用问题

在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些额外的方法和域.但继承并不只是复制基类的接口.当创建一个导出类对象时,该对象包含了一个基类的子对象,这个子对象与你用基类直接创建的对象是一样的,二者区别在于,后者来自于外部,而基类的子对象是被包裹在导出类对象内部. 这就引发出了一个很重要的问题,对基类子对象的正确初始化也是至关重要的(我们可能在子类的使用基类

java新建对象的static块与构造器的执行顺序

前言:本文解决的问题 新建一个对象静态代码块什么时候执行 {}里面的代码什么时候执行 有继承关系时的执行顺序 1.问题出现的背景: 构造器是用来实例化一个对象,当我们使用new关键字来新建对象时,构造器就会被调用.如果class中含有静态代码块(static)和普通代码块(在{}括号下),新建对象时的调用顺序是:静态代码块>{里面的代码}>构造器. 2.例子说明: 2.1代码说明 //父类 public class StaticExample{ { System.out.println(&qu

Java类的调用顺序决定的单例模式

学习Java有一年多,很多基础知识是了解的,有些知道怎么用,但不明白,它是怎么来的. 经常在书上看到介绍类里面的构造方法,静态方法,普通方法与静态变量,调用顺序,但不明白它的真正用处. 今天走进公司时,我突然间,想到了Java的类中,方法,变量的调用顺序重要吗,我一下就想到了单例模式,因为我之前只是知道单例模式的用处,但不明白它怎么来的,单例模式不就是根据类的启动顺序写出来,因为类会先调用static,然后,再是构造函数,可见有些知识点,你只要灵活一点,就大有用处,当然不知,大家认为我的观点对不

Java对象创建阶段的代码调用顺序

在创建阶段系统通过下面的几个步骤来完成对象的创建过程 为对象分配存储空间 开始构造对象 从超类到子类对static成员进行初始化 超类成员变量按顺序初始化,递归调用超类的构造方法 子类成员变量按顺序初始化,子类构造方法调用 本文重点演示第三步到第五步: Grandpa类 1 package com.xinye.test; 2 3 public class Grandpa { 4 { 5 System.out.println("执行Grandpa的普通块"); 6 } 7 static

Java入门记(三):初始化顺序

初始化顺序的规则 1.在一个类的对象实例化时,成员变量首先初始化,然后才调用构造器,无论书写顺序.如果调用构造器前,没有显式初始化,那么会赋默认值. 这样做法的原因可以理解为:构造器执行时可能会用到一些成员变量的初值. 2.static变量早于所有其他的类成员变量初始化,同样无论书写顺序.但是static变量仅在所在类第一次被使用时初始化一次. 3.基类构造器总是在导出类的构造过程中被调用,而且按照继承层级逐渐向上链接(调用顺序则是从基类开始向下).可以理解为,这么做的逻辑关系是在一个类构建时可