黑马程序员_ java高新之类加载器
2014-08-26 16:03
465 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
2)注意:第一个类加载器不是类:就是bootStrap
2)关系他们之间有:根->父->子的关系(当然也可以自己写类加载器,但必须要有父级加载器)
例:
null
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
上面的代码进一步证明了默认类加载器的存在,以及类加载器之间的父子关系。
3)在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载。
祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加
载器的子类,因为没有getChild方法
类加载器中的loadClass方法内部实现了父类委托机制,因此我们没有必要自己覆盖loadClass,否则需要自己去实现父类委
托机制。我们只需要覆盖findClass方法。loadClass方法中调用了findClass方法,使用的是模板设计模式。我们得到了Class文件后,就可以通过defineClass方法将二进制数据转换成字节码。
2)编写一个自己的类加载器,可实现对加密过的类进行加载和解密。
过程:
a、自定义的类加载器必须继承ClassLoader
b、覆盖findClass方法。
c、在findClass方法中对字节码文件进行解密。
d、调用自定义的类加载器对字节码文件进行解密。
自定义类加载器代码:
3)自定义类加载的一个问题:ClassLoaderAttachment类继承Date
如果直接写ClassLoaderAttachment d = (ClassLoaderAttachment)clazz.newInstance();这条语句,编译的时候就会报错,因为此时的
ClassLoaderAttachment在AppClassLoader加载进内存后就无法识别。所以需要通过借助一个父类对象绕过编译器。也就
是:Date d1 = (Date)clazz.newInstance();。
1、类加载器概念
1)通常就是将class字节码文件加载进内存的一个类2)注意:第一个类加载器不是类:就是bootStrap
2、默认类加载器
1)三种默认的类加载器:BootStrap,ExtClassLoader,AppClassLoader2)关系他们之间有:根->父->子的关系(当然也可以自己写类加载器,但必须要有父级加载器)
例:
public static void main(String[] args) throws Exception { System.out.println(ClassLoadTest.class.getClassLoader().getClass().getName());//AppClassLoader加载器 System.out.println(System.class.getClassLoader());//根级类加载器,返回null ClassLoader classLoader = ClassLoadTest.class.getClassLoader(); while(classLoader !=null) { System.out.println(classLoader.getClass().getName()); classLoader = classLoader.getParent();//获得父级类加载器 }<span style="white-space:pre"> </span>System.out.println(classLoader); }打印结果:sun.misc.Launcher$AppClassLoader
null
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null
上面的代码进一步证明了默认类加载器的存在,以及类加载器之间的父子关系。
3)在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载。
3、类加载器的委托机制
1)每个类加载器加载时,都会先委托给上级类加载器,直至到达根类加载器,然后从上到下一级一级的找类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加
载器的子类,因为没有getChild方法
4、自定义类加载器
1)自定义类加载器的原理类加载器中的loadClass方法内部实现了父类委托机制,因此我们没有必要自己覆盖loadClass,否则需要自己去实现父类委
托机制。我们只需要覆盖findClass方法。loadClass方法中调用了findClass方法,使用的是模板设计模式。我们得到了Class文件后,就可以通过defineClass方法将二进制数据转换成字节码。
2)编写一个自己的类加载器,可实现对加密过的类进行加载和解密。
过程:
a、自定义的类加载器必须继承ClassLoader
b、覆盖findClass方法。
c、在findClass方法中对字节码文件进行解密。
d、调用自定义的类加载器对字节码文件进行解密。
自定义类加载器代码:
package com.wit.day2; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; //自己定义的类加载器 public class MyClassLoader extends ClassLoader{ /** * @author shen */ private String path = null; public MyClassLoader(String path) throws Exception//检查文件是否存在 { File f = new File(path); if(!f.isDirectory()) { throw new RuntimeException(path + " is not a directory"); } this.path = path; } //对字节码文件进行加密解密 public static void cypher(InputStream istream,OutputStream ostream) throws Exception { //下面这段代码可能遇到255的字节,当成byte就成了-1 /*byte b = 0; while((b = (byte)istream.read()) != -1) { ostream.write(b ^ 0xff); }*/ int b = 0; while((b = istream.read()) != -1) { ostream.write(((byte)b) ^ 0xff); } } //此类作为类加载器时,此方法起作用 @Override @SuppressWarnings("deprecation") protected Class<?> findClass(String name) { String classFileName = path+"\\"+name+".class"; FileInputStream fis; try { fis = new FileInputStream(classFileName); ByteArrayOutputStream bos = new ByteArrayOutputStream(); cypher(fis, bos); fis.close(); byte[] bytes = bos.toByteArray(); return defineClass(bytes,0,bytes.length); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String [] args) throws Exception { //ClassLoaderAttachment类编译生成的class文件加密后放入文件夹lib中 String srcPath = args[0];//源路径 String destPath = args[1]; //目标路径 FileInputStream fis = new FileInputStream(srcPath); File f = new File(destPath, new File(srcPath).getName());//不用检查目录最后是否有目录分割符 FileOutputStream fos = new FileOutputStream(f); cypher(fis,fos); fis.close(); fos.close(); } }<span style="white-space:pre"> </span>自定义类加载器测试类:
package com.wit.day2; import java.util.Date; //一个普通的类,用于给类加载器加密 public class ClassLoaderAttachment extends Date{ @Override public String toString(){ return "用来加密的类ClassLoaderAttachment"; } }
public class ClassLoaderTest { public static void main(String[] args) throws Exception { <span style="white-space:pre"> </span>Class clazz = new MyClassLoader("lib").loadClass("ClassLoaderAttachment"); <span style="white-space:pre"> </span>Date date = (Date) clazz.newInstance(); <span style="white-space:pre"> </span>System.out.println(date); } }输出结果:用来加密的类ClassLoaderAttachment
3)自定义类加载的一个问题:ClassLoaderAttachment类继承Date
如果直接写ClassLoaderAttachment d = (ClassLoaderAttachment)clazz.newInstance();这条语句,编译的时候就会报错,因为此时的
ClassLoaderAttachment在AppClassLoader加载进内存后就无法识别。所以需要通过借助一个父类对象绕过编译器。也就
是:Date d1 = (Date)clazz.newInstance();。
相关文章推荐
- 黑马程序员-----java提高之类加载器&代理
- 黑马程序员——java高新(枚举、内省、注解、类加载器)
- 黑马程序员-JAVA基础加强之类加载器
- 黑马程序员————JAVA之类加载器
- 黑马程序员-Java基础加强之类加载器
- 黑马程序员之Java基础加强之类加载器
- 黑马程序员——java加强之类加载器
- 黑马程序员—JAVA高新技术之类加载器、动态代理
- java高新之类加载器
- 黑马程序员-Java高新技术之类加载器和代理
- 黑马程序员_java基础之类加载器解析
- 黑马程序员---java高新技术之类加载器
- 黑马程序员---java高新技术之类加载器
- 黑马程序员--【强哥笔记】系列之Java高新技术笔记之类加载器(第7天)
- 黑马程序员__JAVA基础加强--类加载器和代理总结
- 黑马程序员——java代理(含加载器)概述
- 黑马程序员Java高新__泛型
- 黑马程序员----JAVASE高级部分之类加载器
- 黑马程序员之类加载器
- 黑马程序员---张老师高新技术之类加载器.代理与AOP