类加载器(classloader):
java类加载器感觉好难,不是很好理解,只能去理解他最基础的部分。
1.什么是类加载器
根据名字大慨知道他是加载类的工具,就是把一个java类加载到java虚拟机中。java源文件通过编译,生产字节码文件,类加载器就是负责读取字节码文件的,并装换成java.lang.Class类的实例,每个这样的实例表示一个java类。通过实例的newInstance方法创建该类的对象。
2.加载器中种类(主要有3种):
1.跟类加载器(Bootstrap):它用来加载 Java 的核心库,是用c语言来编写的,并不是由Java代码编写的,此类加载器是所有类的祖宗。并不继承自 java.lang.ClassLoader
。
2.扩展类加载器(ExtClassLoader):它用来加载 Java 的扩展库(就是额外的jar比如我们自己写的Java类打成jar就可以放在这里)。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
3.系统类加载器(AppClassLoader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()
来获取它。
(注:跟加载器不是有java编写的)
3. 类加载器的委托机制:
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。自己先不加载,这样如果当父加载器,找到要加载的类就会直接返回会给它的子加载器,如果父类没有找到,它就会让子去找,若是找到就直接返回给它自己,找不到就直接抛出一个ClassNotFoundException。
(总结就一句话:找爸爸)
4.怎么得到一个类的类加载器:
类名.class.getClassLoader().getClass().getname();获取类加载器名称。
5.自定义一个类加载器。
基础知识:
1.自定义一个类加载器必须继承classLoader。
2.明白loaderclass方法(找父亲)和findclass方法。(需要覆盖)
3.明白defilneclass方法。(把一个数组变成一个class字节码)
4.运用了模版方法设计模式。
代码:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
//定义一个类继承Classloader
public class MyClassLoader extends ClassLoader {
public static void main(String[] args) throws Exception {
//定义两个变量,表示源文件和目标目录
String srcPath = args[0];
String destDir = args[1];
//定义一个输入流,并关联地址
FileInputStream fis = new FileInputStream(srcPath);
//得到目标目录路径
String destFileName = srcPath.substring(srcPath.lastIndexOf("\\")+1);
String destPath = destDir+"\\"+destFileName;
//定义输出流,并与目标目录路径相关联
FileOutputStream fos = new FileOutputStream(destPath);
//加密
encrypt(fis,fos);
fis.close();
fos.close();
}
//定义一个文件加密器
public static void encrypt(InputStream is, OutputStream os) throws Exception
{
int b = -1;
while((b=is.read())!= -1)
{//加密^ 0xff
os.write((byte)b ^ 0xff);
}
}
//复写findClass
//定义一个从那加载的目录变量
private String classDir;
public MyClassLoader() {}
public MyClassLoader(String classDir) {
this.classDir = classDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 定义加载器从哪个目录下读
String classFileName = classDir +"\\"+name+".class";
try {//定义输入流关联要读取的目录
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//解密
encrypt(fis,baos);
//转成字节
byte[] bytes = baos.toByteArray();
//将字节转成字节码文件。
return defineClass(bytes, 0, bytes.length);
} catch (FileNotFoundException e) {
//
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
//返回findClass
return super.findClass(name);
}
类加载器是个难点,要多写多用才能好的理解。