AVA父类子类静态代码块、静态变量、构造方法的执行顺序

java中关于子类和父类的构造函数,静态代码块,普通代码块,静态成员变量和普通成员变量的初始化顺序

//父类:

class parent{
   public static String i="我是父类的静态成员变量";
   public String j="我是父类普通的成员变量";

   public parent() {
        System.out.println("我是父类构造");
    }
    static {
        System.out.println("我是父类静态代码块");
    }
    
    {
        System.out.println("我是父类代码块");
    }

}

//子类

public class son extends parent{
    public static String i="我是子类的静态成员变量";
    public String j="我是子类普通的成员变量";

    public son () {
        System.out.println("我是子类构造");
    }
    static {
        System.out.println("我是子类静态代码块");
    }
    {
        System.out.println("我是子类代码块");
    }

}

//测试1

public static void main(String[] args) {
        System.out.println(son.i);
    }

输出结果:(只初始化静态代码块和静态成员变量,静态代码块和静态成员变量的初始化顺序有他们的编写顺序决定,并且父类先于子类)

//测试2

public static void main(String[] args) {
        System.out.println(new son().j);
    }

//测试3

public static void main(String[] args) {
       new parent();
    }

总结:

如果类还没有被加载:
1、先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。
2、执行子类的静态代码块和静态变量初始化。
3、执行父类的实例变量初始化
4、执行父类的构造函数
5、执行子类的实例变量初始化
6、执行子类的构造函数

如果类已经被加载:
则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。
---------------------  
作者:lilamei170607  
来源:CSDN  
原文:https://blog.csdn.net/lilamei170607/article/details/82590287  
版权声明:本文为博主原创文章,转载请附上博文链接!

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
类初始化是类加载过程的最后一个阶段,到初始化阶段,才真正开始执行类中的Java程序代码。虚拟机规范严格规定了有且只有5种情况必须立即对类进行初始化:

    第一种:遇到new、getstatic、putstatic、invokestatic这四条字节码指令时,如果类还没有进行过初始化,则需要先触发其初始化。生成这四条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或设置一个类的静态字段(static)时(被static修饰又被final修饰的,已在编译期把结果放入常量池的静态字段除外)、以及调用一个类的静态方法时。
    第二种:使用Java.lang.refect包的方法对类进行反射调用时,如果类还没有进行过初始化,则需要先触发其初始化。
    第三种:当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
    第四种:当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先执行该主类。
    第五种:当使用JDK1.5支持时,如果一个java.langl.incoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始

执行代码:

package com.spring.partise;

import java.util.Random;

class A{
    static final int numA = Main.rand.nextInt(100);
    static{
        System.out.println("I am A");
    }
}
class B{
    static final int numB = 2;
    static{
        System.out.println("I am B");
    }
}
class C{
    static int numC = 3;
    static{
        System.out.println("I am C");
    }
}
public class Main {
    static Random rand = new Random();
    public static void main(String[] args) throws Exception {
        System.out.println("---------------------------");
        System.out.println(A.numA);//会执行static中的方法
        System.out.println("---------------------------");
        System.out.println(B.numB);//不会执行static中的方法
        System.out.println("---------------------------");
        System.out.println(C.numC);
    }
}

执行结果:

---------------------------
I am A
22
---------------------------
2
---------------------------
I am C
3

总结:如果一个static final值是“编译期常量”,就像static final int numB = 2;那样,那么这个值不需要对B类进行初始化就可以读取。但是,如果只是将一个域设置为static和final的,那不一足以确保这种行为,例如,对static final int numA = Main.rand.nextInt(100);的访问将强制进行类的初始化,因为它不是一个编译期常量。
如果一个static 域不是final,那么在对它访问时,总是要求在它被读取之前,要先进行链接(为这个域分配存储空间)和初始化(初始化该存储空间)就像static int numC = 3;那样!!!
---------------------  
作者:just want to know  
来源:CSDN  
原文:https://blog.csdn.net/dreamzuora/article/details/80188708  
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/SeaSky_Steven/article/details/87453737
今日推荐