谈谈Java虚拟机3――动态扩展 (二)

2014-11-24 03:19:45 · 作者: · 浏览: 2
);

}

} catch (ClassNotFoundException e) {

// If still not found, then invoke findClass in order

// to find the class.

c = findClass(name);

}

}

if (resolve) {

resolveClass(c);

}

return c;

}

两个loadClass()方法都接受装载类型的全限定名装入String类型的name参数。loadClass()的语义和forName()是一样的。如果loadClass()方法已经用String类型的name参数传递的全限定名装载了类型,它会返回这个已经被装载的类型的Class实例。否则,该方法会试图用某种用户定制的方式来装载请求的类型。如果类装载器用定制的方式成功地装载了类型。loadClass()应该返回一个Class的实例,表示新装载的类型。否则方法将抛出ClassNotFoundException异常。

双参数版本的loadClass()中,boolean类型的resolve参数表示是否在装载时执行该类型的连接。连接包含三个步骤:校验、准备、解析。如果resolve参数为true,loadClass()方法会确保在方法返回某个类型的Class实例之前已经装载并连接了该类型。如果resolve参数是false,loadClass()方法仅仅去试图装载请求的类型,而不关心类型是否被连接了。双参数版本的loadClass()是一个过时的方法,实际上从Java1.1开始,resolve参数就没有作用了。通常,应该调用单参数版本的loadClass()时,它会试图装载类型并返回而把连接和初始化类型的进行留给虚拟机去掌握。

loadClass实例:

import java.io.InputStream;

public class MyClassLoader extends ClassLoader {

@Override

public Class< > loadClass(String name) throws ClassNotFoundException {

// TODO Auto-generated method stub

String fileName = name.substring(name.lastIndexOf(".")+1)+".class";

InputStream is = getClass().getResourceAsStream(fileName);

if( is == null){

return super.loadClass(name);

}

try {

byte[] b = new byte[is.available()];

is.read(b);

return defineClass(name,b,0,b.length);

} catch (IOException e) {

e.printStackTrace();

}

return super.loadClass(name);

}

}

package com.xiaoruoen.test;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class ClassLoaderTest {

/**

* @param args

* @throws ClassNotFoundException

* @throws IllegalAccessException

* @throws InstantiationException

* @throws NoSuchMethodException

* @throws SecurityException

* @throws InvocationTargetException

* @throws IllegalArgumentException

*/

public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {

MyClassLoader loader = new MyClassLoader();

Class c = loader.loadClass("com.xiaoruoen.test.Greet");

Object obj = c.newInstance();

Method method = c.getMethod("greet");

method.invoke(obj);

}

}

使用forName()还是调用用户自定义的类装载器的laodClass()方法取决于用户的需要。如果没有特别的类装载器的要求,或许应该用forName(),因为forName()是动态扩展最直接的方法。另外,如果需要请求的类型在装载时就初始化(并且连接)的等方面,则不得不使用forName()。当loadClass()方法返回类型的时候,类型有可能没有被连接,但谳用单参数版本的forName()方法或者调用它的三参数版本并且传递true作为initialize参灵敏的值 时,返回的类型一事实上是已经被连接、初始化过了。

初始化时很重要的。比如JDBC驱动程序通常用forName()调用装载的。因为每一个JDBC驱动程序类的静态方法都用DriverManager注册驱动程序,这样才能被应用程序所使用,驱动程序类必须被初始化,而不是仅仅被加载。如果一个驱动程序被装载了,但是没有初始化,那么类的静态初始化方法就无法被执行,驱动程序就没有在DriverManager中被注册,驱动程序就无法被应用程序使用。

类装载器可以满足一些forNa