我在学习ClassLoader的时候.
参照下面的地址的文章:
深入探讨 Java 类加载器
其中讲到下面的这段:
引用
类加载器的代理模式
类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。在介绍代理模式背后的动机之前,首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器 ClassLoaderA 和 ClassLoaderB 分别读取了这个 Sample.class 文件,并定义出两个 java.lang.Class 类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。下面通过示例来具体说明。代码清单 3 中给出了 Java 类 com.example.Sample。
其中清单3的代码如下:
package com.example;
public class Sample {
private Sample instance;
public void setSample(Object instance) {
this.instance = (Sample) instance;
}
}
一个测试方法如下: 即代码清单5.
public void testClassIdentity() {
String classDataRootPath = "C:\\workspace\\Classloader\\classData";
FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath);
FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath);
String className = "com.example.Sample";
try {
Class<?> class1 = fscl1.loadClass(className);
Object obj1 = class1.newInstance();
Class<?> class2 = fscl2.loadClass(className);
Object obj2 = class2.newInstance();
Method setSampleMethod = class1.getMethod("setSample", java.lang.Object.class);
setSampleMethod.invoke(obj1, obj2);
} catch (Exception e) {
e.printStackTrace();
}
}
文章对此的测试结果是如下:
引用
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at classloader.ClassIdentity.testClassIdentity(ClassIdentity.java:26)
at classloader.ClassIdentity.main(ClassIdentity.java:9)
Caused by: java.lang.ClassCastException: com.example.Sample
cannot be cast to com.example.Sample
at com.example.Sample.setSample(Sample.java:7)
... 6 more
结果解释,如上,和下面:
引用
从 代码清单 5 给出的运行结果可以看到,运行时抛出了 java.lang.ClassCastException 异常。虽然两个对象 obj1 和 obj2 的类的名字相同,但是这两个类是由不同的类加载器实例来加载的,因此不被 Java 虚拟机认为是相同的。
了解了这一点之后,就可以理解代理模式的设计动机了。代理模式是为了保证 Java 核心库的类型安全。所有 Java 应用都至少需要引用 java.lang.Object 类,也就是说在运行的时候,java.lang.Object 这个类需要被加载到 Java 虚拟机中。如果这个加载过程由 Java 应用自己的类加载器来完成的话,很可能就存在多个版本的 java.lang.Object 类,而且这些类之间是不兼容的。通过代理模式,对于 Java 核心库的类的加载工作由引导类加载器来统一完成,保证了 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。
不同的类加载器为相同名称的类创建了额外的名称空间。相同名称的类可以并存在 Java 虚拟机中,只需要用不同的类加载器来加载它们即可。不同类加载器加载的类之间是不兼容的,这就相当于在 Java 虚拟机内部创建了一个个相互隔离的 Java 类空间。这种技术在许多框架中都被用到,后面会详细介绍。
但是,
但是我测试在机子上测试的时候,运行了N多次都没有见到,异常出来,我是第一次希望出现异常,
但是没有出现.
我测试代码如下,其它的没有变,就是包名变了,和一些路径变了.:
package guet.dream.jvm;
public class Sample {
private Sample instance;
public void setSample(Object instance){
this.instance = (Sample)instance;
}
}
测试方法:
package guet.dream.jvm;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ClassIndentityTest {
/**
* @param args
*/
public static void main(String[] args) {
String classDataRootPath = "guet/dream/jvm/";
FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath);
FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath);
String className = "guet.dream.jvm.Sample";
try {
Class<?> clazz1 = fscl1.loadClass(className);
Class<?> clazz2 = fscl2.loadClass(className);
Object obj1 = clazz1.newInstance();
Object obj2 = clazz2.newInstance();
Method setSampleMethod = clazz1.getMethod("setSample", Object.class);
setSampleMethod.invoke(obj1, obj2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
下面是原文中,我稍加修改的ClassLoader.
package guet.dream.jvm;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir){
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
byte[] classData = getClassData(name);
if(classData == null){
throw new ClassNotFoundException();
}else{
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] getClassData(String className) {
String path = classNameToPath(className);
InputStream in;
try {
in = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while((bytesNumRead = in.read(buffer)) != -1 ){
baos.write(buffer,0,bytesNumRead);
}
return baos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String classNameToPath(String className) {
return rootDir+File.separatorChar+className.replace('.', File.separatorChar)+".class";
}
}
运行结果没有任何异常,希望,有对这方面了解的,各位网友,测试或者给解答下.
这好像是我发的第一个贴吧!
我的JDK信息如下:
引用
banxi1988@banxi:~$ java -version
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.2) (6b22-1.10.2-0ubuntu1~11.04.1)
OpenJDK Server VM (build 20.0-b11, mixed mode)
banxi1988@banxi:~$
分享到:
相关推荐
在Java编程语言中,ClassLoader是核心组件之一,它负责加载类到JVM(Java虚拟机)中执行。本文将深入探讨ClassLoader的工作原理和类加载机制,帮助开发者理解这个至关重要的概念。 1. 类加载机制概述 Java的类加载...
在Java虚拟机(JVM)中,类加载器(ClassLoader)是至关重要的组成部分,它负责查找和加载类的字节码文件。理解ClassLoader的工作机制对于深入掌握Java应用程序的运行至关重要。这里我们将详细讨论ClassLoader的运行...
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。了解和掌握ClassLoader的工作原理以及如何自定义ClassLoader对于深入理解Java应用程序的运行机制非常有帮助。以下是对...
编译类加载器是一种特殊的类加载器,它在加载类之前会先对源代码进行编译。这种类型的类加载器对于那些需要在运行时动态生成或修改代码的应用场景非常有用。 #### 五、Java 2中的类加载器变化 Java 2平台引入了...
Java提供了三个基础类加载器:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader,它们按照层次结构加载类。 1. **自定义ClassLoader**:Java允许我们创建自定义的ClassLoader,这通常用于实现动态...
Java的类加载机制是其运行的核心...理解ClassLoader的工作原理以及如何动态加载类,对于优化程序性能、实现高级功能,如插件系统、模块化等,具有重要意义。开发者可以根据需求自定义加载策略,以满足特定的应用场景。
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java ...
在 JVM 运行过程中,类加载器会形成一个层次结构,包括引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和系统类加载器(System ClassLoader)。 引导类加载器(Bootstrap ...
如果父类加载器无法完成加载任务,子类加载器才会尝试自己加载类。 这种模式的优点在于它可以有效防止类的重复加载,确保Java核心库的类型安全。比如,如果用户尝试使用Application ClassLoader加载rt.jar中的类,...
Java中ClassLoader类加载学习总结 ...ClassLoader类的应用非常广泛,例如在Web应用程序中,ClassLoader类可以用来加载不同类库的类,在Android应用程序中,ClassLoader类可以用来加载不同的apk文件等等。
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
类加载遵循“双亲委托模型”,即当一个类加载器收到加载类的请求时,它会首先委托父类加载器尝试加载,只有当父类加载器无法找到对应的类时,才会自己尝试加载。这样保证了基础类库的一致性,同时也允许Web应用覆盖...
ClassLoader是JVM中的一个重要组件,它的主要任务是加载类的二进制数据,转换为Class对象,并供Java应用程序使用。本文将深入浅出地探讨JVM ClassLoader的工作原理和相关知识点。 首先,ClassLoader可以分为三种...
该电子书详细介绍了java虚拟机类加载机制,对于深入理解jvm工作原理有很好的帮助作用,对于初学java,有一定工作经验的小伙伴来说是一本提高自身java素养,夯实自己java基本技能的“葵花宝典”。
这是一种设计模式,当类加载器接收到加载类的请求时,它首先会将请求委派给其父类加载器处理,只有在父类加载器无法加载时,子类加载器才会尝试加载。这种模型保证了类的唯一性,避免了类的重复加载和冲突。 4. **...
总结来说,Java应用程序类加载器是Java程序执行的关键部分,它负责在运行时找到并加载类,而它的灵活性和可配置性为开发者提供了强大的能力来适应各种复杂的应用场景。理解并掌握类加载器的工作原理,能帮助我们更好...
`DexFile`类提供了从.dex文件加载类的方法,例如`loadDex()`。一旦类加载到内存,就可以像使用普通类一样使用它们。 在实际应用中,动态加载dex文件通常伴随着一些挑战,比如权限问题、多版本兼容、类冲突等。例如...
在Java编程语言中,类加载机制(ClassLoader)是理解JVM(Java Virtual Machine)工作原理的关键部分。它负责将.class文件从磁盘加载到内存中,使得Java程序能够执行。这个过程包括加载、验证、准备、解析和初始化五...
- **`findClass()`方法**:重写`ClassLoader`中的`findClass()`方法,该方法用于实际加载类的二进制数据。首先调用`loadClassData()`方法从文件系统读取类文件数据,然后使用`defineClass()`方法将二进制数据转换为`...