miracle just wanna be better

静态代码块,静态属性和有继承时的执行顺序

2019-07-12
miracle

有继承时静态代码块的输出顺序

判断程序的输出

class ClassA{
	static{
		System.out.println("In ClassA Static");
	}
	public ClassA(){
		System.out.println("ClassA()");
	}
}
class ClassB{
	static{
		System.out.println("In ClassB Static");
	}
	public ClassB(){
		System.out.println("ClassB()");
	}
}
class ClassC extends ClassB{
	static{
		System.out.println("In ClassC Static");
	}
	public ClassC(){
		System.out.println("ClassC()");
	}
}
class MyClass{
	static ClassA ca = new ClassA();
	ClassC cc = new ClassC();
	static{
		System.out.println("In MyClass Static");
	}
	public MyClass(){
		System.out.println("MyClass()");
	}
	
}
public class Test1 {
	public static void main(String[] args) {
		MyClass mc1 = new MyClass();
		MyClass mc2 = new MyClass();
		 System.out.println(mc1.cc == mc2.cc);
		 System.out.println(mc1.ca == mc2.ca);
	}

}

结果

  1. In ClassA Static 优先加载静态属性–>加载ClassA类–>加载ClassA静态代码块
  2. ClassA() 加载ClassA构造函数
  3. In MyClass Static 加载Myclass静态代码块
  4. In ClassB Static 在执行Myclass构造函数体前加载属性–>进入加载ClassC类,ClassC继承自ClassB–>执行ClassB静态代码块
  5. In ClassC Static 然后加载ClassC的静态代码块
  6. ClassB() 执行父类ClassB的构造函数
  7. ClassC() 执行子类ClassC的构造函数
  8. MyClass() MyClass属性加载完,执行MyClass构造函数体

  9. ClassB() 因为静态属性只执行一次,所以执行Class cc = new ClassC(); –> 静态代码块只执行一次–>父类ClassB构造函数
  10. ClassC() 执行子类ClassC构造函数
  11. MyClass() MyClass属性加载完,执行MyClass构造函数体
  12. false 每次new一个对象,cc也会new一个新的对象,地址不同
  13. true 因为是静态属性,所以只执行一次,是同一个对象,地址一样

结论

  • 静态代码块在类加载的时候就运行
  • 如果有静态属性,静态属性优先于静态代码块
  • 在有继承时,先加载父类静态代码块 –> 加载子类静态代码块 –> 父类构造 –> 子类构造
  • 属性优先于构造函数,先执行构造函数第一句 –> 加载属性 –> 再回到执行构造函数体

无继承时,静态代码块和代码块的执行顺序

例子: Demo1.java

public class Demo1 {
	Demo2 dd = new Demo2();
	static{
		//可以写代码段
		System.out.println("Demo1.static code");
	}
	public Demo1(){
		System.out.println("Demo1.构造函数");
	}
	
	{
		System.out.println("Demo1.类中的代码块");
		
	}
	
	private static  int age =10;
	private int temp = 10;
	public void testMethod1(){
		age = 100;
		temp = 100;
	}
	public static void testMethod2(){
		age = 1000;
	
	}
	public static void main(String[] args) {
		//1.类加载,Demo1类加载方法区,且开辟了空间age,没有temp空间
		//2.new Demo1()在堆中开辟d1空间,d1中的temp空间也开辟,初值是10,age空间没有
	 Demo1 d1 = new Demo1();
	 //调用testMethod1()把d1中的temp改成100,把方法区中的age也改成了100
	 d1.testMethod1();
	 //从方法区中取出age的数据100
	 System.out.println(age);
	 //从堆空间中的d1中的temp取出的数据是100
	 System.out.println(d1.temp);
	 
	 //没有类加载,直接new对象在堆空间中,d2.temp=10
	 Demo1 d2 = new Demo1();
	 System.out.println(d2.temp);
	 //从方法区中取出的数据,是d1.testMethod方法之前存的100
	 System.out.println(age);
	 
	 Demo1.testMethod2();
	}	

Demo2.java

public class Demo2 {
	static{
		System.out.println("Demo2.静态代码块");
	}
	{
		System.out.println("Demo2.类代码块");
	}
	public Demo2(){
		System.out.println("Demo2.构造函数");
	}
}

结果

  • a.第一个类加载,执行第一个类的静态代码块
  • b.第一个类包含第二个类作为第一个类的属性(注意,new和不new的问题)
    new: >执行第二个类的静态代码块 执行第二个类的代码块 执行第二个类的构造方法 不new: >不加载第二个类

  • c.执行第一个类的代码块 b在c前,执行顺序是a,b,c,d c在b前,执行顺序是a,c,b,d
  • d.执行第一个类的构造函数

下一篇 集合

Comments

Content