java中的.class文件必须有classloader这些类加载器来加载。
这个就是java中的classloader层次图。
classloader的入口就是这个函数:public Class<?> loadClass(String name)
各个loader之间有委托关系,或者没有。
loader是有势力范围的,最重要的,最关键的核心类,是由最底层的loader来控制的,比如BootStarp,它加载的是java核心类比如: java.lang.Object,如果你想用AppClassLoader来加载java.lang.Object是不可能的,会有安全的异常爆出。(具体原理没弄清楚)。
比方我在网上摘抄一段:
package test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
public Class<?> loadClass(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);
try {
InputStream ins = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = ins.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String classNameToPath(String className) {
return rootDir + File.separatorChar
+ className.replace('.', File.separatorChar) + ".class";
}
}
package test;
public class Node {
private String name="xiaoming";
private int age=88;
/**
* @return the name
*/
public Node()
{
System.out.println("###"+this.getName().getClass().getClassLoader());
//这是个隐式load调用,Node被FileSystemClassloder载入,下面该载入java.lang.Object,因为
//它是java.lang.String的超类,同样java.lang.Object,也是被FileSystemClassLoader中的方法loadClass
//调用,但是它和BootStarp loader中的java.lang.Object同名,所以是加载不进来的,所以这里应该委托一下
//调用ClassLoader的getSystemClassLoader()来获得appclassLoader来加载这个java.lang.Object,同时
//AppClassLoader也是委托extClassLoader,ExtclassLoader最后委托Bootstarp来load这个class文件的(不排除
//有缓存的机制). 显然委托机制是必要的,因为为了你的类不可避免要调用核心包里面的类,自己的loader加载核心包类
//会起冲突。
String www=new String("www");
System.out.println("wwwwww"+www.getClass().getClassLoader());
}
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
package test;
import java.lang.reflect.Method;
public class main {
public static void main(String args[])
{
//String classDataRootPath = "H:\\bin";
String classDataRootPath = "G:\\tomcat_source\\apache-tomcat-6.0.35-src\\apache-tomcat-6.0.35-src\\java\\bin";
FileSystemClassLoader fscl1 = new FileSystemClassLoader(classDataRootPath);
FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath);
String className = "test.Node";
try {
Class<?> class1 = fscl1.loadClass(className);
Object obj1 = class1.newInstance();
//Node node=new Node();
System.out.println("--->"+obj1.toString()+ " "+obj1.getClass().getClassLoader()+" parent:"+class1.getClassLoader().getParent());
//System.out.println("--->"+node.getClass().getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}
}