JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass(String name)方法:
使用的是双亲委托模式:
jvm启动时,会启动jre/rt.jar里的类加载器:bootstrap classloader,用来加载java核心api;然后启动扩展类加载器ExtClassLoader加载扩展类,并加载用户程序加载器AppClassLoader,并指定ExtClassLoader为他的父类;
当类被加载时,会先检查在内存中是否已经被加载,如果是,则不再加载,如果没有,再由AppClassLoader来加载,先从jar包里找,没有再从classpath里找;
如果自定义loader类,就会存在这命名空间的情况,不同的加载器加载同一个类时,产生的实例其实是不同的;
Java代码
publicClass> loadClass(String name)throwsClassNotFoundException {
returnloadClass(name,false);
}
publicClass> loadClass(String name)throwsClassNotFoundException {
returnloadClass(name,false);
}
loadClass(String name)方法再调用loadClass(String name, boolean resolve)方法:
◆ name - 类的二进制名称
◆ resolve - 如果该参数为 true,则分析这个类
Java代码
protectedsynchronizedClass> loadClass(String name,booleanresolve)
throwsClassNotFoundException
{
// First, check if the class has already been loaded
//JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,如果一个Class已经被加载过,则直接从缓存中获取
Class c = findLoadedClass(name);
if(c ==null) {
try{
if(parent !=null) {
c = parent.loadClass(name, false);
} else{
c = findBootstrapClass0(name);
}
} catch(ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if(resolve) {
resolveClass(c);
}
returnc;
}
protectedsynchronizedClass> loadClass(String name,booleanresolve)
throwsClassNotFoundException
{
// First, check if the class has already been loaded
//JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,如果一个Class已经被加载过,则直接从缓存中获取
Class c = findLoadedClass(name);
if(c ==null) {
try{
if(parent !=null) {
c = parent.loadClass(name, false);
} else{
c = findBootstrapClass0(name);
}
} catch(ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if(resolve) {
resolveClass(c);
}
returnc;
}
如果ClassLoader并没有加载这个class,则调用findBootstrapClass0:
Java代码
privateClass findBootstrapClass0(String name)
throwsClassNotFoundException
{
check();
if(!checkName(name))
thrownewClassNotFoundException(name);
returnfindBootstrapClass(name);
}
privateClass findBootstrapClass0(String name)
throwsClassNotFoundException
{
check();
if(!checkName(name))
thrownewClassNotFoundException(name);
returnfindBootstrapClass(name);
}
该方法会调用check()方法来判断这个类是否已经初始化,并且通过checkName(name)来判断由name指定的这个类是否存在***调用findBootstrapClass(name):
Java代码
privatenativeClass findBootstrapClass(String name)
throwsClassNotFoundException;
privatenativeClass findBootstrapClass(String name)
throwsClassNotFoundException;
而这个findBootstrapClass方法是一个native方法,这是我们的root loader,这个载入方法并非是由JAVA所写,而是C++写的,它会最终调用JVM中的原生findBootstrapClass方法来完成类的加载。
如果上面两个都找不到,则使用findClass(name)来查找指定类名的Class:
Java代码
protectedClass> findClass(String name)throwsClassNotFoundException {
thrownewClassNotFoundException(name);
}
protectedClass> findClass(String name)throwsClassNotFoundException {
thrownewClassNotFoundException(name);
}
JDK5.0中的说明:
使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。默认实现抛出一个ClassNotFoundException。
所以,我们在自定义类中,只需要重写findClass()即可。
MyClassLoader类:
Java代码
publicclassMyClassLoaderextendsClassLoader {
privateString fileName;
publicMyClassLoader(String fileName) {
this.fileName = fileName;
}
protectedClass> findClass(String className)throwsClassNotFoundException {
Class clazz = this.findLoadedClass(className);
if(null== clazz) {
try{
String classFile = getClassFile(className);
FileInputStream fis = newFileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new
ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while(true) {
inti = fileC.read(buffer);
if(i ==0|| i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
byte[] bytes = baos.toByteArray();
clazz = defineClass(className, bytes, 0, bytes.length);
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
returnclazz;
}
privatebyte[] loadClassBytes(String className)throws
ClassNotFoundException {
try{
String classFile = getClassFile(className);
FileInputStream fis = newFileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new
ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while(true) {
inti = fileC.read(buffer);
if(i ==0|| i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
returnbaos.toByteArray();
} catch(IOException fnfe) {
thrownewClassNotFoundException(className);
}
}
privateString getClassFile(String name) {
StringBuffer sb = newStringBuffer(fileName);
name = name.replace('.', File.separatorChar) +".class";
sb.append(File.separator + name);
returnsb.toString();
}
}
publicclassMyClassLoaderextendsClassLoader {
privateString fileName;
publicMyClassLoader(String fileName) {
this.fileName = fileName;
}
protectedClass> findClass(String className)throwsClassNotFoundException {
Class clazz = this.findLoadedClass(className);
if(null== clazz) {
try{
String classFile = getClassFile(className);
FileInputStream fis = newFileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new
ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while(true) {
inti = fileC.read(buffer);
if(i ==0|| i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
byte[] bytes = baos.toByteArray();
clazz = defineClass(className, bytes, 0, bytes.length);
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
returnclazz;
}
privatebyte[] loadClassBytes(String className)throws
ClassNotFoundException {
try{
String classFile = getClassFile(className);
FileInputStream fis = newFileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new
ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while(true) {
inti = fileC.read(buffer);
if(i ==0|| i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
returnbaos.toByteArray();
} catch(IOException fnfe) {
thrownewClassNotFoundException(className);
}
}
privateString getClassFile(String name) {
StringBuffer sb = newStringBuffer(fileName);
name = name.replace('.', File.separatorChar) +".class";
sb.append(File.separator + name);
returnsb.toString();
}
}
该类中通过调用defineClass(String name, byte[] b, int off, int len)方法来定义一个类:
Java代码
protectedfinalClass> defineClass(String name,byte[] b,intoff,intlen)
throwsClassFormatError
{
returndefineClass(name, b, off, len,null);
}
protectedfinalClass> defineClass(String name,byte[] b,intoff,intlen)
throwsClassFormatError
{
returndefineClass(name, b, off, len,null);
}
注:MyClassLoader加载类时有一个局限,必需指定.class文件,而不能指定.jar文件。该类中的大部分代码是从网上搜索到的,是出自一牛人之笔,只是不知道原帖在哪,希望不会被隐藏。
MainClassLoader类:
Java代码
publicclassMainClassLoader {
publicstaticvoidmain(String[] args) {
try{
MyClassLoader tc = newMyClassLoader("F:\\OpenLib\\");
Class c = tc.findClass("Test");
c.newInstance();
} catch(ClassNotFoundException e) {
e.printStackTrace();
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(InstantiationException e) {
e.printStackTrace();
}
}
}
publicclassMainClassLoader {
publicstaticvoidmain(String[] args) {
try{
MyClassLoader tc = newMyClassLoader("F:\\OpenLib\\");
Class c = tc.findClass("Test");
c.newInstance();
} catch(ClassNotFoundException e) {
e.printStackTrace();
} catch(IllegalAccessException e) {
e.printStackTrace();
} catch(InstantiationException e) {
e.printStackTrace();
}
}
}
***是一个简单的Test测试类:
Java代码
publicclassTest
{
publicTest() {
System.out.println("Test");
}
publicstaticvoidmain(String[] args) {
System.out.println("Hello World");
}
}
原文链接:http://huangcanqin.iteye.com/blog/1273170
【编辑推荐】
【责任编辑:小林 TEL:(010)68476606】
点赞 0