您的位置:首页 > 职场人生

黑马程序员_Java类加载器

2014-08-08 22:28 197 查看
----------- android培训java培训、java学习型技术博客、期待与您交流! ------------
 
Blog11_1 类加载器

(1)类加载器: 在java中要使用一个类,就必须先把这个类的class文件加载到JVM中去进行一些处理然后才能使用,在这个过程中,加载class文件和对class文件进行处理的类就叫类加载器。

Java虚拟机中可以安装多个类加载器,但系统默认的类加载器主要有三个:

BootStrap:该加载器没有父加载器,它负责加载虚拟机的核心类库,如java.lang.*等;它的实现依赖于底层操作系统,属于虚拟机的实现的一部分,它并没有继承java.lang.ClassLoader类,它是用C++写的。

ExtClassLoader: 它从java.ext.dirs系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre\lib\ext子目录(扩展目录)下加载类库,如果把用户创建的JAR文件放在这个目录下,也会自动由扩展类加载器加载。

AppClassLoader: 它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,它是用户自定义的类加载器的默认父加载器,系统类加载器是纯Java类,是java.lang.ClassLoader类的子类。

主要管辖范围和关系如下图所示:



(2)类加载器的委托机制

类加载器的委托机制流程:

A.首先当前线程的类加载器去加载线程中的第一个类;
B.如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
C.还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器;
D.当所有父类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的子类。
总结下来就是:
  每个加载器都优先尝试用父类加载,若父类不能加载则自己尝试加载;若成功则返回Class对象给子类,若失败则告诉子类让子类自己加载。所有都失败则抛出异常。
Blog11_2自定义类加载器

(1)自定义一个自定义类加载器的步骤:
A.      让这个类继承ClassLoader类;
B.      在这个类中重写findClass方法(那为什么不重写loadClass()方法呢?因为loadClass()方法中有父类委托机制,如果在这个类中重写了loadClass()方法,就会使父类委托机制丧失)。
C.      创建自定义类对象,并调用loadClass()方法(注意:虽然表面上没有调用在自定义类中重写的findClass()方法,其实当我们查看loadClass()源码时发现,在loadClass方法内部调用了findClass()方法)。
 
Blog11_3一个自定义类加载器实现解密功能

在日常开发中为了保护自己的代码的安全性,常常需要对自己的代码进行加密,但怎样能让代码安全,又能方便自己使用呢?此时用一个自定义类加载器实现解密自己加密的代码不失为一种好的办法。

原理:在自定义类加载器的findClass方法中写入解密的代码,当在自己电脑上用这个自定义类加载器加载Class文件的同时就能对加密的class文件进行解密。

实现的步骤如下:

(1)    首先写一个能进行简单加密的类:

代码如下:

public classEncryption {
private String sourceFile;
private String destFile;
// sourceFile为要加密的文件路径
// destFile为加密后的文件存放路径
public static void encryption(String sourceFile, String destFile) throws Exception {
InputStream is = new FileInputStream(sourceFile);
OutputStream os = new FileOutputStream(destFile);
int a = 0;
while ((a = is.read()) != -1){
os.write(a+19881006);
}
is.close();
os.close();
System.out.println("加密成功!");
}
}


上面加密的过程很简单,就是为class二进制文件中的每一个字节加上19881006。

(2)自定义类加载器实现解密功能

private  String dirPath ;
public MyClassLoader(String dirPath) {
super();
this.dirPath=dirPath;
}
@Override
protected Class<?>findClass(String name) throws ClassNotFoundException {
// 需要解密的文件路径
String filePath = dirPath+ "\\"+ name + ".class";
byte[] bys = null;
try {
// 调用decrypt()方法对指定目录下得文件解密,并返回解密后的二进制数组;
bys= decrypt(filePath);
}catch(Exception e) {
e.printStackTrace();
}
if (bys != null) {
return defineClass(null, bys, 0, bys.length);
}else{
return super.findClass(name);
}
}
//解密的方法
public static byte[] decrypt(StringencryptCode) throwsException {
InputStream is = new FileInputStream(encryptCode);
ByteArrayOutputStreamb os = new ByteArrayOutputStream();
int a = 0;
while ((a = is.read()) != -1){
bos.write(a-19881006);
}
byte[] bys =bos.toByteArray();
is.close();
bos.close();
return bys;
}


defineClass方法的功能是:将一个 byte 数组转换为 Class 类的实例。

(2) 定义一个接受测试的类(本例中是Secret类),并在测试类中测试它:

public classTest {
public static void main(String[] args) throws Exception {
Encryption.encryption("D:\\WorkSpace\\类加载器\\bin\\test\\Secret.class",
"cipher\\encryption\\Secret.class");
//Class clas =Class.forName("test.Secret");
Class clas=new MyClassLoader("D:\\WorkSpace\\类加载器\\cipher\\encryption").loadClass("Secret");
Constructor con = clas.getConstructor();
Object obj = con.newInstance();
Method md = clas.getMethod("print");
md.invoke(obj);
}
}


测试结果:当使用自己的类加载器加载被加密的class文件时能使用其中的方法,当不用自己的类加载器加载时则不能使用加密的class文件。

总结:使自定义类加载器继承ClassLoader类,并重写其中的findClass方法,然后调用defineClass方法返回一个Class 类的实例,即完成了一个自定义类加载器。

----------------------- android培训java培训、java学习型技术博客、期待与您交流! ----------------------
详情请查看:http://edu.csdn.net/heima

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息