JAVA中 类的初始化

类的初始化流程

加载一个类A时(执行该类的Java代码 或者 是 new 一个 该类的对象)

首先读取该类 是否存在基类B 通过extends 判断,

如果有基类B,读取其基类B,直到读取到最初始的基类C

从最初始的基类C进行初始化,再直到逐步初始化其派生类B直到加载类A

 

首先从类的 static 域开始加载,首先声明 static 只加载一次,将类中的 static 属性字段,方法,构造器,main函数一一加载到 static 域 中, 再次 new 一个类A的对象,static将不再加载,而是会先检查static域中是否有值。

当然 一个类加载也是分先后顺序的:

  1. static int i; static play();静态对象数据 (由上至下)
  2. Windows w1; Gird gird; 对象数据(由上至下)
  3. A() 构造器 构造器也是静态方法 只是没有明确使用static

 

/**
 * 类的初始化顺序
 */
class Window {
	Window(int i) {
		System.out.println("Window + " + i);
	}
}

class House {
    // 对象数据是 由上至下加载的 w1 - > w2 - > w3
	Window w1 = new Window(1);

	House() {
		System.out.println("House()");
		w3 = new Window(33);
	}

	Window w2 = new Window(2);

	void f() {
		System.out.println("f() ");
	}

	Window w3 = new Window(3);
}

public class OrderOfInitialization {
	public static void main(String[] args) {
		House h = new House();
		h.f();
	}
}

结果打印

Window + 1
Window + 2
Window + 3
House()
Window + 33
f() 

通常都是 static方法中(构造器也算是static修饰了-隐式)初始化字段,原则上不会调用其他方法

但是如果调用方法呢? 一般安全的做法是只能调用final方法

但是如果调用了普通方法,那么这个示例会让你明白

初始化 派生类 时候,虽然从基类开始一步步向下初始赋值,但是基类中static方法中调用的方法都会追溯到底层只使用最底层派生类的方法,

只是由于初始化顺序的原因部分字段是还未赋值,只能为系统默认初始值

abstract class BaseWithPrint {
	public BaseWithPrint() {
		print();
		test();
	}

	public abstract void print();
	
	public void test(){
		System.out.println("test BaseWithPrint!");
	}
}

class DerivedWithPrint extends BaseWithPrint {
	int i = 47;
 
	public DerivedWithPrint() {
		print();
		test();
	}
	
	public void print() {
		System.out.println("i = " + i);
	}
	
	public void test(){
		System.out.println("test DerivedWithPrint!");
	}
}

class LastedWithPrint extends DerivedWithPrint {
	int i = 100;

	public void print() {
		System.out.println("i = " + i);
	}
	
	public void test(){
		System.out.println("test LastedWithPrint!");
	}
}

public class E03_Initialization {
	public static void main(String args[]) {
		LastedWithPrint dp = new LastedWithPrint();
		dp.print();
	}
}

打印输出:

i = 0
test LastedWithPrint!
i = 0
test LastedWithPrint!
i = 100

那么把print加上final修饰会怎么样呢?

class DerivedWithPrint extends BaseWithPrint {
    int i = 47;

	public DerivedWithPrint() {
		print();
		test();
	}
	
	public final void print() {
		System.out.println("i = " + i);
	}
	
	public void test(){
		System.out.println("test DerivedWithPrint!");
	}
}

class LastedWithPrint extends DerivedWithPrint {
	int i = 100;

	
	public void test(){
		System.out.println("test LastedWithPrint!");
	}
}

public class E03_Initialization {
	public static void main(String args[]) {
		LastedWithPrint dp = new LastedWithPrint();
		dp.print();
	}
}

 打印输出:

i = 0
test LastedWithPrint!
i = 47
test LastedWithPrint!
i = 47

我们发现 如果追溯不到最底层的派生类,实际的过程是从基类开始追溯下层直到遇见 final 关键字结束,这一层就作为该方法的取值层了。

真是有趣的初始化呀!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值