ClassLoader
有2个重要方法:
Class<?> loadClass(String name, boolean resolve)
Class<?> findClass(String name)
//双亲委派查找类
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
// 在双亲中查不到,就可以到这个自定义实现查找类的方法去加载类
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
自定义ClassLoader
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class MyClassLoader extends ClassLoader {
private String libPath;
public MyClassLoader(String path) {
libPath = path;
}
/**
* 重写查找类方法
*
* 默认走双亲委派,最后找不到通过findClass到指定目录中去加载class
*
* @param name
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String fileName = getFileName(name);
File file = new File(libPath, fileName);
try {
FileInputStream is = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
try {
while ((len = is.read()) != -1) {
bos.write(len);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] data = bos.toByteArray();
is.close();
bos.close();
return defineClass(name, data, 0, data.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
/**
* 获取要加载 的class文件名
* @param name
* @return
*/
private String getFileName(String name) {
int index = name.lastIndexOf('.');
if (index == -1) {
return name + ".class";
} else {
return name.substring(index + 1) + ".class";
}
}
}
编写测试类
public interface ISpeak {
void speak();
void write(String value);
}
public class Speak implements ISpeak {
public static String name = "one";
@Override
public void speak() {
System.out.println("speak" + name);
}
@Override
public void write(String value) {
name=value;
}
}
将speak类生成字节码后,放到 F:\lib\appone 和 F:\lib\apptwo 目录中,然后将speak.java 删除,重新编译项目,后面通过classload 加载指定目录的 class 字节码文件
测试例子
/**
* 将编译好的speak.class 放到 F:\lib\appone 和 F:\lib\apptwo 目录中
*
* 演示不同类加载器加载,不同目录中,同1个命名空间类,类被加载后已经不是同1个类了
*/
public class ClassloaderApp {
public static void main(String[] args) {
ISpeak speak1=null;
ISpeak speak2=null;
ISpeak speak3=null;
ISpeak speak4=null;
final MyClassLoader myClassLoader1 = new MyClassLoader("F:\\lib\\appone");
try {
Class cls1 = myClassLoader1.loadClass("cn.sing.classload.defineclassload.speak.Speak");
System.out.println(cls1.getClassLoader().toString());
if(cls1 != null){
try {
speak1 = (ISpeak)cls1.newInstance();
speak1.speak();
speak3 = (ISpeak)cls1.newInstance();
speak3.speak();
//Method method = cls1.getDeclaredMethod("speak",null);
//method.invoke(obj, null);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
final MyClassLoader myClassLoader = new MyClassLoader("F:\\lib\\apptwo");
try {
Class c = myClassLoader.loadClass("cn.sing.classload.defineclassload.speak.Speak");
System.out.println(c.getClassLoader().toString());
if(c != null){
try {
speak2 = (ISpeak)c.newInstance();
speak2.speak();
speak4 = (ISpeak)c.newInstance();
speak4.speak();
//Method method = c.getDeclaredMethod("speak",null);
//method.invoke(obj, null);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//默认AppClassLoader加载
System.out.println(ISpeak.class.getClassLoader().toString());
// speak1 myClassLoader1
System.out.println(speak1.getClass().getClassLoader().toString());
// speak1 父加载器是 AppClassLoader ,但是 speak1 不是通过 AppClassLoader 加载的
System.out.println(speak1.getClass().getClassLoader().getParent().toString());
// speak2 myClassLoader2
System.out.println(speak2.getClass().getClassLoader().toString());
// speak2 父加载器是 AppClassLoader ,但是 speak2 不是通过 AppClassLoader 加载的
System.out.println(speak2.getClass().getClassLoader().getParent().toString());
//改变静态变量值
speak1.write("app-one");
speak2.write("app-two");
//speak1 和 speak3 属于同1个加载器
speak1.speak();
speak3.speak();
//speak2 和 speak4 属于同1个加载器
speak2.speak();
speak4.speak();
}
}
运行结果
cn.sing.classload.defineclassload.MyClassLoader@3764951d
speakone
speakone
cn.sing.classload.defineclassload.MyClassLoader@4d7e1886
speakone
speakone
sun.misc.Launcher$AppClassLoader@18b4aac2
cn.sing.classload.defineclassload.MyClassLoader@3764951d
sun.misc.Launcher$AppClassLoader@18b4aac2
cn.sing.classload.defineclassload.MyClassLoader@4d7e1886
sun.misc.Launcher$AppClassLoader@18b4aac2
speakapp-one
speakapp-one
speakapp-two
speakapp-two