证明:同一个JVM里面一个Class可以被load多次

本文通过实例演示了JVM如何能够加载两个相同名称但由不同类加载器加载的类。通过观察静态域初始化的过程,验证了同一类在不同类加载器作用下被视为不同类的现象。
部署运行你感兴趣的模型镜像
对CLASSLOADER有过研究的人都知道,JVM使用CLASSLOADER在JVM中分隔出许多命名空间,不同的命名空间中的类是不“互见的”,这个“不互见”的意思是彼此不知道对方的存在,比如classloader1加载类A,在classloader2所构建的命名空间里面类就不知道的。classloader2因为不知道classloader2加载了A,所以它自己也可以以自己的方式来加载“另一个”类A。这样其实,在JVM内就存在两个Class A了。、

上面的理论其实在看过“深入JVM”后就知道了。最近又翻了翻这本书,想起两年前与同事说的那句话“JVM可以loader两个同样的类,那你证明下呀”,当时没当回事,反正也是懵懵懂懂证明不了,避而不谈。现在呢,有时间也有能力了,那就来证明下吧。

这个证明的逻辑是:

因为class在被加载的时候,其static域会被初始化,那么一个类被加载两次加载进jvm的话,那么static域就会被初始化两次。

那现在只要证明static的域是可以被初始化两次就可以了。那怎么证明呢?

只要每次在初始化的时候能给static域赋上不同的值,区分出来,在特定的时候打印出来

就可以了。

看下下面的代码片段,事情可能就清楚了。

被加载的类 IntProducer:

import java.util.Random;

public class IntProducer
{
//用随机值来加载静态域赋值,如果被加载两次age应该会是不同的值
public static int age = getRandom();

public static int getRandom()
{
Random ran = new Random(System.nanoTime());
int rand = ran.nextInt(10);
System.out.println("IntProducer 被加载,产生随机数:"+rand);
return rand;

}

}


用于加载IntProducer的类:


public class LoaderSample4
{

public static void main(String[] args) throws Exception
{
System.out.println(LoaderSample4.class.getClassLoader());


URL[] us =
{ new URL("file://D:/") };

ClassLoader loader1 = new URLClassLoader(us);
Class c1 = loader1.loadClass("IntProducer");

System.out.println(c1.getClassLoader()+":"+c1.getField("age").getInt(c1));

//再加载一次
ClassLoader loader2 = new URLClassLoader(us);
Class c2 = loader2.loadClass("IntProducer");
System.out.println(c2.getClassLoader()+":"+c2.getField("age").getInt(c2));

}

}

您可能感兴趣的与本文相关的镜像

TensorFlow-v2.9

TensorFlow-v2.9

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

### Java虚拟机(JVM)的概念及工作原理 #### 定义 Java虚拟机(JVM)是一种抽象计算设备,它作为软件层运行于实际的操作系统之上[^2]。它的主要作用是提供一种统一的环境,使得编译后的Java字节码可以在任何支持JVM的平台上运行,从而实现“一次编写,到处运行”的跨平台特性。 #### 工作原理概述 1. **加载阶段** 当启动一个Java程序时,JVM会通过加载器将`.class`文件加载到内存中[^1]。这一过程包括验证、准备、解析和初始化四个子阶段,确保加载符合规范并准备好用于后续操作。 2. **字节码执行** 加载完成后,JVM会使用解释器逐条解释执行字节码,或者通过即时编译器(Just-In-Time, JIT Compiler)将频繁使用的部分字节码编译为本地机器码以提高效率。这种方式既保证了灵活性又提升了性能。 3. **内存管理** JVM内部维护了一套复杂的内存模型,主要包括堆(Heap)、栈(Stack)、方法区(Method Area)、PC寄存器和本地方法栈等区域[^3]。其中,堆是最核心的部分,用来存储对象实例;而栈则保存局部变量表和操作数栈等内容。 4. **垃圾回收机制** 自动化的内存管理是JVM的一大特色。通过内置的垃圾收集器(Garbage Collector),它可以识别不再被引用的对象,并适时释放其所占用的空间[^4]。常见的GC策略有标记-清除法、复制算法以及分代收集技术等。 5. **线程支持** JVM允许多个独立的任务并发执行,这得益于其对多线程的良好支持。除了普通的应用级线程外,还存在一些特殊的守护线程,它们负责诸如垃圾回收这样的后台服务任务。 6. **全量垃圾回收 (Full GC)** 特定条件下会发生全面清理活动——即所谓的Full GC事件[^5]。这情形通常涉及老年代资源耗尽或是元空间容量达到上限等情况。 ```python # 示例:简单模拟JVM加载与执行逻辑 def load_class(class_name): """ 似于JVM中的加载过程 """ print(f"Loading class {class_name} into memory.") def execute_bytecode(bytecode): """ 解释或编译执行字节码 """ if bytecode.startswith('invoke'): compile_to_native(bytecode) def compile_to_native(bytecode): """ 即时编译示例函数 """ native_code = f"# Native code generated from {bytecode}" run(native_code) def run(code): """ 执行最终生成的目标代码 """ print(f"Executing: {code}") if __name__ == "__main__": clazz = "SampleClass" load_class(clazz) bytecodes = ["ldc", "iconst_0", "invoke"] for bc in bytecodes: execute_bytecode(bc) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值