有继承时静态代码块的输出顺序
判断程序的输出
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);
}
}
结果
- In ClassA Static 优先加载静态属性–>加载ClassA类–>加载ClassA静态代码块
- ClassA() 加载ClassA构造函数
- In MyClass Static 加载Myclass静态代码块
- In ClassB Static 在执行Myclass构造函数体前加载属性–>进入加载ClassC类,ClassC继承自ClassB–>执行ClassB静态代码块
- In ClassC Static 然后加载ClassC的静态代码块
- ClassB() 执行父类ClassB的构造函数
- ClassC() 执行子类ClassC的构造函数
-
MyClass() MyClass属性加载完,执行MyClass构造函数体
- ClassB() 因为静态属性只执行一次,所以执行Class cc = new ClassC(); –> 静态代码块只执行一次–>父类ClassB构造函数
- ClassC() 执行子类ClassC构造函数
- MyClass() MyClass属性加载完,执行MyClass构造函数体
- false 每次new一个对象,cc也会new一个新的对象,地址不同
- 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.执行第一个类的构造函数