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

1.没有继承的情况

单独一个类的场景下,初始化顺序为依次为 静态变量和静态代码块(看两者的书写顺序),继承的基类的构造函数,成员变量,被调用的构造函数。

代码呈现:

public class Test {

public static void main(String[] args) {

Son son = new Son();

}

}

class Son {

public Son() {

System.out.println("this is son.");

}

public Son(int age) {

System.out.println("son is " + age + " years old.");

}

private Height height = new Height(1.8f);

static {

System.out.println("this is static code");

}

public static Gender gender = new Gender(true);

}

class Height {

public Height(float height) {

System.out.println("initializing height " + height + " meters.");

}

}

class Gender {

public Gender(boolean isMale) {

if (isMale) {

System.out.println("this is a male.");

} else {

System.out.println("this is a female.");

}

}

}

this is static code

this is a male.

initializing height 1.8 meters.

this is son.

2.继承的情况

稍微修改一下代码,添加两个基类,让Son继承Father, Father继承Grandpa。

继承的情况就比较复杂了。由于继承了基类,还将往上回溯,递归地调用基类的无参构造方法。

在我们的例子中,在初始化静态数据后,会先往上追溯,调用Father的默认构造方法,此时再往上追溯到Grandpa的默认构造方法。

注:如果在子类的构造方法中,显式地调用了父类的带参构造方法,那么JVM将调用指定的构造方法而非默认构造方法。

基类和子类均有静态数据,成员变量和构造方法的场景

我们继续修改代码,让其最终呈现如下:

public class Test {

public static void main(String[] args) {

Son son = new Son();

}

}

class Grandpa {

public Grandpa() {

System.out.println("this is grandpa.");

}

public Grandpa(int age) {

System.out.println("grandpa is " + age + " years old.");

}

private Height height = new Height(1.5f);

public static Gender gender = new Gender(true, "grandpa");

static {

System.out.println("this is static code");

}

}

class Father extends Grandpa {

public Father() {

System.out.println("this is father.");

}

public Father(int age) {

System.out.println("father is " + age + " years old.");

}

private Height height = new Height(1.6f);

public static Gender gender = new Gender(true, "father");

}

class Son extends Father {

public Son() {

super(50);

System.out.println("this is son.");

}

public Son(int age) {

System.out.println("son is " + age + " years old.");

}

private Height height = new Height(1.8f);

public static Gender gender = new Gender(true, "son");

}

class Height {

public Height(float height) {

System.out.println("initializing height " + height + " meters.");

}

}

class Gender {

public Gender(boolean isMale) {

if (isMale) {

System.out.println("this is a male.");

} else {

System.out.println("this is a female.");

}

}

public Gender(boolean isMale, String identify) {

if (isMale) {

System.out.println(identify + " is a male.");

} else {

System.out.println(identify + " is a female.");

}

}

}

grandpa is a male.

this is static code

father is a male.

son is a male.

initializing height 1.5 meters.

this is grandpa.

initializing height 1.6 meters.

father is 50 years old.

initializing height 1.8 meters.

this is son.

在我们的示例中,加载顺序应该是这样的:

Grandpa 静态数据

Father 静态数据

Son 静态数据

Grandpa 成员变量

Grandpa 构造方法

Father 成员变量

Father 构造方法

Son 成员变量

Son 构造方法

一般来说,顺序如下:

1.首先是父类的静态变量和静态代码块(看两者的书写顺序);

2.第二执行子类的静态变量和静态代码块(看两者的书写顺序);

3.第三执行父类的成员变量赋值

4.第四执行父类类的构造代码块

5.第五执行父类的构造方法

6.执行子类的构造代码块

7.第七执行子类的构造方法

总结,也就是说虽然客户端代码是new 的构造方法,但是构造方法确实是在整个实例创建中的最后一个调用。

先静态:具体是先父静态>子静态。

先父后子:先父的全部,然后后子的全部。

优先级:父类>子类,静态代码块>非静态代码块>构造函数(与位置前后无关系)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值