`
ayaoxinchao
  • 浏览: 80850 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

Java中对类的主动引用和被动引用

阅读更多

 

在Java代码中,有些类看上去初始化了,但其实没有。例如定义一定长度某一类型的数组,看上去数组中所有的元素已经被初始化,实际上一个都没有。

对于类的初始化,虚拟机规范严格规定了只有对该类进行主动引用时,才会触发。而除此之外的所有引用方式称之为对类的被动引用,不会触发类的初始化。


虚拟机规范严格地规定了有且仅有四种情况是对类的主动引用,即必须立即对类进行初始化。四种情况如下:

1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行初始化,则需要先触发其初始化。

(1)使用new关键字实例化对象

/**
 * @author Perlin.Yao
 */
public class NewClass {

	static {
		System.out.println("NewClass init!");
	}
	
}
/**
 * @author Perlin.Yao
 */
public class Initialization1 {
	
	public static void main(String[] args) {
		new NewClass();
	}

}
// 输出结果
NewClass init!

(2)读取类的静态成员变量

 

/**
 * @author Perlin.Yao
 */
public class StaticAttributeClass {
	
	public static int value = 1;
	
	public static void staticMethod() {
		//System.out.println("staticMethod invoked");
	}
	
	static {
		System.out.println("StaticAttributeClass init!");
	}

}
/**
 * @author Perlin.Yao
 */
public class Initialization2 {
	
	public static void main(String[] args) {
		// 1.读取静态变量
		int x = StaticAttributeClass.value;
	}

}
// 输出结果
StaticAttributeClass init!

 (3)设置类的静态成员变量

 

 

/**
 * @author Perlin.Yao
 */
public class Initialization2 {
	
	public static void main(String[] args) {
		// 2.设置静态变量
		StaticAttributeClass.value = 2;
	}

}
// 输出结果
StaticAttributeClass init!

 (4)调用类的静态方法

/**
 * @author Perlin.Yao
 */
public class Initialization2 {
	
	public static void main(String[] args) {
		// 3.调用静态方法
		StaticAttributeClass.staticMethod();
	}

}
// 输出结果
StaticAttributeClass init!

 

2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。

/**
 * @author Perlin.Yao
 */
public class ReflectClass {
	
	static {
		System.out.println("ReflectClass init!");
	}

}
/**
 * @author Perlin.Yao
 */
public class Initialization3 {
	
	public static void main(String[] args) throws Exception {
		Class classB = Class.forName("jvm.init.ReflectClass");
	}

}
// 输出结果
ReflectClass init!

 3.当一个类初始化的时候,如果发现其父类还没有初始化,则需要先对其父类进行初始化。

/**
 * @author Perlin.Yao
 */
public class SuperClass {
	
	static {
		System.out.println("SuperClass init!");
	}
	
	public static int value = 123;

}
/**
 * @author Perlin.Yao
 */
public class SubClass extends SuperClass {
	
	static {
		System.out.println("SubClass init!");
	}

}
/**
 * @author Perlin.Yao
 */
public class Initialization4 {
	
	public static void main(String[] args) {
		new SubClass();
	}

}
// 输出结果
SuperClass init!
SubClass init!

4.当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类

其实就是public static void main(String[] args)所在的那个类

 

下面来列举几个对类被动引用的例子:

 

1.通过子类引用父类的的静态字段,不会导致子类初始化

/**
 * @author Perlin.Yao
 */
public class SuperClass {
	
	static {
		System.out.println("SuperClass init!");
	}
	
	public static int value = 123;

}
/**
 * @author Perlin.Yao
 */
public class SubClass extends SuperClass {
	
	static {
		System.out.println("SubClass init!");
	}

}
/**
 * @author Perlin.Yao
 */
public class NotInitialization1 {
	
	public static void main(String[] args) {
		int x = SubClass.value;
	}

}
// 输出结果
SuperClass init!

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

/**
 * @author Perlin.Yao
 */
public class NotInitialization2 {
	
	public static void main(String[] args) {
		SuperClass[] sca = new SuperClass[10];
	}

}
// 无任何输出

 3.常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

/**
 * @author Perlin.Yao
 */
public class ConstClass {
	
	static {
		System.out.println("ConstClass init!");
	}
	
	public static final int value = 123;

}
/**
 * @author Perlin.Yao
 */
public class NotInitialization3 {
	
	public static void main(String[] args) {
		int x = ConstClass.value;
	}

}
// 无任何输出结果

 

参考书籍:《深入Java虚拟机》

                  《深入理解Java虚拟机》

 

 

 

 

 

 


 

 

 

 

分享到:
评论

相关推荐

    浅谈Java中对类的主动引用和被动引用

    浅谈Java中对类的主动引用和被动引用 Java 中的类引用可以分为两种:主动引用和被动引用。理解这两种引用机制对于 Java 程序的正确执行和优化至关重要。 一、主动引用 主动引用是指在 Java 程序中明确地使用某个...

    Java虚拟机JVM类加载初始化

    Java虚拟机JVM类加载初始化是Java程序运行过程中的关键环节,它负责将类的字节码文件加载到内存中并进行相应的处理,以便程序能够正确执行。在Java中,类加载器(Classloader)扮演着核心角色。下面将详细讨论类加载...

    Java虚拟机----类的加载过程.docx

    Java虚拟机规范规定了5种触发初始化的主动引用情况: 1. 使用new关键字实例化对象。 2. 访问或修改类的静态字段(不包括final修饰的静态常量)。 3. 调用类的静态方法。 4. 初始化主类(包含main方法的类)。 5. ...

    JAVA 基础培训,JDK和JVM,核心类的介绍和使用

    被动引用,如反射访问或子类对父类的引用,则不会触发类的加载。 #### 三、自定义ClassLoader的意义 虽然JVM自带的ClassLoader功能强大,但在特定情况下,自定义ClassLoader有其必要性: 1. **安全性增强**:在...

    Java虚拟机JVM类加载学习笔记

    本文主要探讨JVM的类加载机制,包括类加载、连接、初始化等关键过程,以及类的主动使用和被动使用的情况。 首先,我们要理解**类加载**的作用。JVM的类加载器(ClassLoader)负责将编译后的`.class`文件加载到内存...

    Java类加载机制 PDF 下载

    Java类加载机制是Java运行时环境中的核心组成部分,它负责将编译后的字节码(.class文件)加载到Java虚拟机(JVM)中,使得程序能够执行。这一过程涉及多个步骤,包括加载、验证、准备、解析和初始化。理解类加载...

    Java类加载原理浅析

    例如,你可以实现热部署,动态加载网络上的类,或者对类进行加密解密后再加载等。 除了基础的类加载,还有**类的全限定名**、**类加载器的层次结构**、**类的生命周期**等知识点。理解这些概念对于进行JVM调优、...

    java类加载过程详解.doc

    Java 类加载过程是Java虚拟机(JVM)在运行时动态加载类的机制,它涉及类的生命周期中的几个关键步骤,包括装载、连接、初始化和卸载。下面将详细阐述这些过程。 1. 装载 装载阶段是类加载的起始点,主要分为三个...

    深入Java虚拟机-ClassLoader.pptx

    Java程序对类的使用分为主动使用和被动使用。只有在六种特定情况下,类才会被初始化:创建类实例、访问或修改静态变量、调用静态方法、反射操作、初始化子类以及JVM启动时指定的启动类。其他情况被视为被动使用,...

    Java类装载过程_.docx

    需要注意的是,除了以上六种主动用法,其他对类的被动用法不会触发初始化。例如,仅通过子类引用父类的静态字段不会导致父类的初始化。 这个过程保证了类的安全性和正确性,避免了非法代码的执行。理解并掌握Java类...

    Java虚拟机

    相反,“被动使用”是指不触发类加载的一些操作,如通过数组定义来引用类(不会触发此类的初始化),或者仅存在对类的引用但并未实际使用。 了解这些基本概念后,我们还需要知道类的生命周期,包括加载、验证、准备...

    Java中类与对象的生命周期

    4. **使用**:类的使用包括主动引用和被动引用。主动引用会导致类实例的创建,而被动引用则不会。例如,创建类数组仅引用类而不实例化,引用类的常量也不会导致初始化。 5. **卸载**:类的卸载发生在所有条件满足时...

    Java虚拟机介绍。不错的书啊

    Java程序对类的使用方式主要分为两大类:主动使用和被动使用。主动使用包括创建类的实例、访问或修改静态变量、调用静态方法、反射操作、子类初始化以及作为启动类。这些情形下,JVM会触发类的初始化过程。相反,...

    类加载机制PPT+代码

    在提供的资源中,"JAVA 虚拟机运行机制-培训资料交流(刘晓阳).ppt"很可能包含了关于类加载机制的详细讲解和实例分析,可以帮助深入理解这一主题。而"test.zip"可能包含了一些示例代码或测试用例,用于实践和演示类...

    Java面试资料之JVM相关

    在Java面试中,JVM相关知识是常见的话题,尤其是类的生命周期和加载机制。 类的生命周期主要包括七个阶段:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化...

    java-class-lifecycle.rar_class

    初始化阶段是类生命周期中最关键的部分,它执行类的静态初始化语句(static块)和对静态变量的赋值操作。只有当类被首次主动使用时(如创建类实例、调用静态方法或访问静态字段),才会触发初始化。如果类只被被动...

    北京圣思园深入Java虚拟机

    Java程序对类的使用方式可以分为**主动使用**和**被动使用**两大类: - **主动使用**: - 创建类的实例。 - 访问或修改静态变量。 - 调用静态方法。 - 反射(例如使用`Class.forName()`)。 - 初始化一个类的...

    18.类加载器.doc

    Java对类的使用分为两类:主动使用和被动使用。只有当类被主动使用时,JVM才会进行初始化。主动使用包括: - 创建类实例 - 访问类的静态变量或对其赋值 - 调用类的静态方法 - 使用反射加载类 - 初始化类的子类 - ...

    深入理解Java 类加载全过程

    初始化阶段是在类或接口被首次主动引用时触发的。以下四种情况会触发初始化: - 使用`new`关键字实例化对象。 - 访问或修改类的静态字段(非final的)。 - 调用类的静态方法(`static`关键字声明的)。 - 使用反射...

Global site tag (gtag.js) - Google Analytics