图片与代码引用他人,侵权请告知。
类加载的时机:
1.new关键字
2.get,set静态变量
3.反射
4.使用子类时,发现父类没有初始化时
5.调用静态方法时。
6.程序入口类。
类的加载过程:
加载,验证,准备,解析,初始化。
双亲委派模式:
1.启动类加载器:
JAVA_HOME/lib目录下的jar
2.扩展类加载器:
JAVA_HOME/lib/ext目录下的jar
3.应用程序类加载器:
加载构建工具指定的classpath目录
4.自定义类加载器
从下至上,在加载前都要询问父类加载器是否可以加载。这样就保证了,父类加载的都是子类需要的基础类。当父类表示超出加载范围,那么子类再去加载。这样就保证了同一类在系统就只会出现一次。
以上的父子关系是通过组合复用父类代码实现的,不是继承实现的。
列外的情况:(不使用双亲委派模式)
热加载模式
当前线程加载器应对Native代码调用用户代码的情况。
列子:
自定义加载器的使用场景:
当你需要加密你的字节码的时候,或者你的字节码在网络上或者数据库中时。
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
public class MyClassLoader extends ClassLoader
{
public MyClassLoader()
{
}
public MyClassLoader(ClassLoader parent)
{
super(parent);
}
protected Class<?> findClass(String name) throws ClassNotFoundException
{
File file = new File("D:/People.class");
try{
byte[] bytes = getClassBytes(file);
//defineClass方法可以把二进制流字节组成的文件转换为一个java.lang.Class
Class<?> c = this.defineClass(name, bytes, 0, bytes.length);
return c;
}
catch (Exception e)
{
e.printStackTrace();
}
return super.findClass(name);
}
private byte[] getClassBytes(File file) throws Exception
{
// 这里要读入.class的字节,因此要使用字节流
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
WritableByteChannel wbc = Channels.newChannel(baos);
ByteBuffer by = ByteBuffer.allocate(1024);
while (true){
int i = fc.read(by);
if (i == 0 || i == -1)
break;
by.flip();
wbc.write(by);
by.clear();
}
fis.close();
return baos.toByteArray();
}
}