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
版权声明:本文为博主原创文章,转载请附上博文链接!