类的主动使用和被动使用

  • 2022 年 2 月 23 日
  • 笔记

 

即判断是否执行<clinit>方法

被动使用有可能会加载类(JVM规范里没有说明),根据不同虚拟机实现,如果在加载的过程中,遇到了.class文件的缺失或者存在错误,类加载器只会在首次主动使用它们时才会报错,如果一直没有主动使用,则不会报错

主动

一,使用new关键字或者通过反射、克隆、反序列化

二,调用类的静态方法。

三,当使用类、接口的静态字段时(final修饰特殊考虑)。

四,当使用java.lang.reflect包中的方法反射类的方法时。

五,当初始化子类时,如果发现其父类还没有进行过初始化,则需要先触发父类的初始化

interface Parent {
Thread thread = new Thread(){ //匿名内部类
{
System.out.println(“Thread…Parent”);
}
};
}
class Child implements Parent {
public static int b = 5;
}
public class Test04 {
public static void main(String[] args) {
System.out.println(Child.b);
}
}
//接口继承或者实现接口类,只有当程序首次使用特定接口的静态字段时,才会导致该接口的初始化,而且是引用类型的
//例子中初始化Chlid但并没有初始化父接口。

六,如果一个接口定义了default方法,那么直接实现或者间接实现该接口的类的初始化,该接口要在其之前被初始化。

interface Parent {
Thread thread = new Thread(){ //匿名内部类
{
System.out.println(“Thread…Parent”);
}
};
default void a(){
System.out.println(“dafsdaf”);
}
}
class Child implements Parent {
}
public class Test04 {
public static void main(String[] args) {
Child child=new Child();
}
}

七,jvm启动时被标明为启动类的类(如Java Test、main方法所在的类)

八,动态语言,当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在类。

被动

一,static final的常量

class F{
static final int count = 1;
static{
System.out.println(“Initialize class F”);
}
}
public class Test6 {
public static void main(String[] args) {
int x = F.count;
}
}
//static final的常量,F的class文件删掉,也不影响程序的正常执行,其在编译阶段就会存入调用类的常量池中

class F{
static final String s = UUID.randomUUID().toString();
static{
System.out.println(“Initialize class F”);
}
}
public class Test6 {
public static void main(String[] args) {
String x = F.s;
}
}
//运行期确定不是常量

二,当通过子类引用父类的静态变量,不会导致子类初始化

class Dfather{
static int count = 1;
static{
System.out.println(“Initialize class Dfather”);
}
}
class Dson extends Dfather{
static{
System.out.println(“Initialize class Dson”);
}
}
public class Test4 {
public static void main(String[] args) {
int x = Dson.count;
}
}
//会加载Dson,但不会初始化,不同虚拟机不同,可通过参数 -verbose:class查看

class C{
static int a=1;
static {
System.out.println(“wdfghjkldfgh”);
}
}
public class P extends C{
static {
System.out.println(“fdsfsf”);
}
public static void main(String[] args) {
System.out.println(P.a);
}
}
//注意若运行类直接继承则会初始化子类

三,通过数组定义类引用,不会触发此类的初始化

class E{
static{
System.out.println(“Initialize class E”);
}
}
public class Test5 {
public static void main(String[] args) {
E[] e = new E[10];
}
}