对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));
}
}
分享到:
相关推荐
- **栈帧**:每个线程都有一个独立的虚拟机栈,栈中存放的是一个个栈帧,每个栈帧代表一次方法调用。 - **局部变量表**:保存方法参数和局部变量。 - **操作数栈**:用于临时存放计算过程中的中间结果。 **方法调用...
JVM的设计目标是实现“一次编写,到处运行”。 2. **类加载机制**:JVM通过类加载器将.class文件加载到内存中。这包括加载、验证、准备、解析和初始化五个阶段。双亲委派模型是类加载器的基本工作模式,确保了类的...
新创建的对象通常分配在年轻代,经过多次垃圾回收后未被回收的对象会被晋升到老年代。 2. **内存碎片处理**:JVM通过垃圾回收机制来减少内存碎片,提高内存利用率。 3. **内存分配策略**:为了提高性能,JVM可能会...
深拷贝是指完全复制一个对象及其内部引用的对象,形成完全独立的新对象。这样即使原始对象发生变化,也不会影响到拷贝后的对象。 总之,在Java开发过程中,深入了解JVM的类加载机制以及相关的类加载器类型对于提高...
在Bea安装完毕的目录下可以看到有一个类似于jrockit81sp1_141_03的文件夹。这就是Bea新JVM所在目录。不同于HotSpot把Java字节码编译成本地码,它预先编译成类。JRockit还提供了更细致的功能用以观察JVM的运行状态,...
1. **Java虚拟机(JVM)**:JVM是Java平台的核心组件,它负责执行Java字节码,提供了一个跨平台的运行环境。JVM实现了内存管理、垃圾回收、类加载机制等,确保了Java程序的“一次编写,到处运行”。 2. **Go语言**...
标题中的“tEST_ALOAD_1.RAR_The Test”可能是一个测试压缩文件,其中包含了名为“Test_aload_1.java”的源代码文件。在Java编程语言中,".java"文件是源代码文件,用于编写Java应用程序。"ALOAD"在Java字节码中是一...
当对象在新生代中经过多次GC仍然存活下来时,将会被提升到老年代。 - **永久代**:在Java 8之前,用于存放类元数据,包括类定义、常量池、静态变量等信息。在Java 8中已被元空间(Metaspace)取代。 #### 四、编写...
- **老年代(Old Generation)**:对象在新生代经过多次垃圾回收后,或者较大的对象直接被分配到老年代。 2. **栈区(Stack)**:栈区主要用于存储线程私有的数据,例如局部变量表、操作数栈、动态链接、方法出口等...
紧随魔术数之后,是两个字节的版本信息,分别表示主版本号和次版本号,主版本号表示class文件可以被执行的JVM版本,次版本号表示class文件的兼容性。class文件中的版本信息告诉JVM运行class文件的Java环境版本。 接...
而小对象则可能在Eden区快速分配,经历一次或多次Minor GC后晋升到老年代。如果对象在 Eden 区分配失败,且Survivor区也无法容纳,就会触发Full GC,这通常是性能问题的潜在信号。 通过JDK源码分析,我们可以了解到...
《深入理解JVM的源代码》是周志明先生的一部深度解析Java虚拟机(JVM)的经典著作。这本书以源代码为线索,详细剖析了JVM的工作原理,旨在帮助开发者深入理解Java运行机制,提升程序性能优化的能力。在本文中,我们...
【JVM综合53问】是一份针对Java虚拟机(JVM)的全面问答文档,旨在帮助Java开发者深入理解和优化JVM。以下是其中涉及到的一些关键知识点: 1. **为何学习JVM?** - **面试需求**:在招聘中,企业越来越重视技术...
2. **JVM内存结构**:JVM内存主要分为堆内存(包括新生代和老年代)和栈内存(每个线程一个栈),还有方法区(包含持久代)。新生代进一步划分为Eden区和两个Survivor区(From和To),默认比例为8:1:1。 3. **内存...
例如,`aload_0`用于从局部变量表中加载第一个引用类型变量,`iadd`用于执行加法操作。源代码会包含各种字节码指令的示例,以帮助理解它们如何协同工作。 4. 内存管理:JVM的内存管理主要包括垃圾收集(Garbage ...
2. 类加载器(classloader):JVM内部包含一个或多个类加载器,用于加载Java类文件(.class文件),并将类信息加载到JVM中。类加载器在Java中是一种动态加载类的方式,是实现JVM跨平台能力的重要组件。 3. 字节码...
当频繁地使用相同的反射操作时,如获取Class对象、构造函数或方法,预加载这些信息并存储在一个缓存中可以显著提高性能。这种缓存机制减少了重复的JVM查找,从而降低了运行时的开销。 缓存思路通常有以下几种实现...
- 老年代:存放经过多次GC后存活下来的对象。 - 持久代(Permanent Generation):存放类元数据,如类定义、常量池等。(注:Java 8中已改为元空间) #### 9. GC用的引用可达性分析算法中,哪些对象可作为GC ...
可以通过不同类加载器加载同一个类的不同版本。 2. **线程上下文类加载器** - **默认设置**:通常默认为系统类加载器。 - **用途**:主要用于资源和服务提供者 SPI(Service Provider Interface)的实现类加载。...