包括:
一. 编译机制
二. 类加载机制
三.自定义类加载器
一. 编译机制
编译主要是把 .java 文件转换为 .class 文件。其中转换后的 .class 文件就包含了元数据,方法信息等一些信息。比如说元数据就包含了 Java 文件中声明的常量,也就是我们所说的常量池。
- BootStrap Loader:它所加载的都是 JVM 中最底层的类。
- ExtClassLoader:用于加载 Java 的一些库。
- AppClassLoader:它主要由 java.class.path 来指定。
- 对于隐式的方法:主要使用 new 关键字。
- 对于显示的方法:可以由 java.lang.Class 的 forName() 方法加载。也可以由 java.lang.ClassLoader的loadClass() 方法加载。
自定义类加载器可以选择继承ClassLoader类,重写里面的方法来实现。里面有三个重要的方法,一个是loadClass()方法,一个是findClass()方法,一个是defineClass()方法。
对于loadClass(String name,Boolean resolve)方法:不推荐重写,因为loadClass()方法做的工作主要为实现双亲委托模型,我们重写的话可能会破坏该模型,并且也增加自己的开发难度。
对于defineClass(String name,byte[] b,int off,int len)方法,主要用于将原始字节转换为Class对象,也不需要我们重写。
对于findClass(String name)方法,根据名称来查找类。把.class文件的内容放入一个byte[]数组中,供defineClass()方法使用。一般我们就重写这个方法。在这个方法中,我们重新定义从哪里,怎么样读取文件内容。这样我们就可以把从本机上改为从网络上得到类,从而实现自定义类加载器。
总而言之:1.继承ClassLoader类。2.重写findClass(String name)方法。 3.在这个方法里面我们重新定义从哪里,怎么读取文件内容到byte[]数组中,供defineClass()使用。
例子:
public class Sample{
public int v1 = 1;
public Sample(){
System.out.println(“Sample is load by :” + this.getClass().getClassLoader());
}
}
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader{
private String name;
private String path = ”d:\\”;
private final String fileType = ”.class”;
public MyClassLoader(String name){
super();
this.name = name;
}
public MyClassLoader(ClassLoader parent, String name){
super(parent);
this.name = name;
}
@Override
public String toString(){return this.name;}
public String getName(){return name;}
public void setName(String name){this.name = name;}
public String getPath(){return path;}
public void setPath(String path){this.path = path;}
public String getFileType(){return fileType;}
protected Class<?> findClass(String name) throws ClassNotFoundException{
byte[] data = this.loadClassData(name);
return this.defineClass(name, data, 0, data.length);
}
private byte[] loadClassData(String name){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
try{
this.name = this.name.replace(“.”, ”\\”);
is = new FileInputStream(new File(path + name + fileType));
baos = new ByteArrayOutputStream();
int ch = 0;
while (-1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray();
}catch (Exception e){
e.printStackTrace();
}finally{
try{
is.close();
baos.close();
}catch (Exception e){
e.printStackTrace();
}
}
return data;
}
public static void showClassLoader(ClassLoader loader) throws Exception{
Class clazz = loader.loadClass(“Sample”);
Object object = clazz.newInstance();
}
public static void main(String[] args) throws Exception{
MyClassLoader loader1 = new MyClassLoader(“loader1″);
loader1.setPath(“d:\\loader1\\”);
MyClassLoader loader2 = new MyClassLoader(loader1, ”loader2″);
loader2.setPath(“d:\\loader2\\”);
MyClassLoader loader3 = new MyClassLoader(null, ”loader3″);
loader3.setPath(“d:\\loader3\\”);
showClassLoader(loader2);
showClassLoader(loader3);
}
}
总结:
- 编译机制:把 .Java 文件转化为.class文件。
- 类加载机制:通过 3个 ClassLoader 来加载 .class 文件,采用双亲委托模型,能达到一定的安全效果。
- 自定义ClassLoader:继承ClassLoader类,里面有3个方法,loadClass() - 实现双亲委托模型,findClass() - 定义如何读取文件内容,,defineClass() - 把byte[] 数组内容转化为Class对象;我们需要重写findClass()方法定义如何读取文件内容到byte[]数组。