类加载阶段中“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作放到Java虚拟机外部去实现(实现的代码叫做“类加载器(Class Loader)”),以便让应用程序自己决定如何获取所需的类。
类加载器起初是为了满足Java Applet的需求设计出来的,虽然在如今基本被淘汰,但在类层次划分、OSGi、程序热部署、代码加密等领域大放异彩,成为Java技术体系中的一块重要的基石。
- 类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远超类加载阶段。对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每个类加载器,都拥有一个独立的类名称空间。
- 两个类即使来源于同一个Class文件,被同一个Java虚拟机加载,只要加载他们的虚拟机不同,那这两个类就必定不相等。
- 这里的相等,包括代表类的Class对象的equals()方法、isAssignableForm()方法、isInstance()方法的返回结果,也包括使用instanceof关键字做对象所属关系判定等各种情况。
package com.test;
import java.io.IOException;
import java.io.InputStream;
/**
* 类加载器与instanceof关键字
* @author huyl
*
*/
public class ClassLoaderTest {
public static void main(String[] args) throws Exception {
ClassLoader myLoader = new ClassLoader(){
public Class<?> loadClass(String name) throws ClassNotFoundException{
try{
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is = (InputStream) getClass().getResourceAsStream(fileName);
if( is == null ){
return super.loadClass(name);
}
byte[] b = new byte[is.available()];
is.read(b);
return defineClass(name, b,0, b.length);
}catch(IOException e){
throw new ClassNotFoundException(name);
}
}
};
Object obj = myLoader.loadClass("com.test.ClassLoaderTest").newInstance();
System.out.println(obj.getClass());
System.out.println(obj instanceof com.test.ClassLoaderTest);
}
}
输出结果
class com.test.ClassLoaderTest
false
分析原因:
这是因为Java虚拟机中同时存在了两个ClassLoaderTest类,一个是由虚拟机的应用程序类加载器所加载的,另外一个是由我们自定义的类加载器加载的,虽然他们都来自第一个Class文件,但在Java虚拟机中仍然是两个互相独立的类,做对象所属类型检查时的结果自然为false。
《深入理解Java虚拟机》学习笔记
网友评论