张孝祥高薪技术5类加载器

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

1   类加载器
    Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。
System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
    .getName());//sun.misc.Launcher$AppClassLoader
System.out.println(System.class.getClassLoader());//null
表示:类System是一个特殊的类,由null加载的

2   类加载器也是Java类
    因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。

3   父子关系的树形结构
    Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认
采用系统类装载器为其父级类加载。
                                 BootStrap-------------->JRE/lib/rt.jar
    ExtClassLoader---------->JRE/lib/ext/*.jar
     System classLoader--AppClassLoader---------->CLASSPATH指定的所有jar或目录

                    MyClassLoader  ItcastClassLoader------>传智博客的指定目录

4   类加载器的委托机制
    当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
        首先当前线程的类加载器去加载线程中的第一个类。
        如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
        还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
        每个类加载器加载类时,又先委托给其上级类加载器。
        当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有
    getChild方法,即使有,那有多个儿子,找哪一个呢?
       对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader。

5   能不能自己写个类叫java.lang.System?
    不能!
    因为:为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,也就是总是使用爸爸们能找到的类,这样总是使用java系统提供的System

 

6   模板方法设计模式
    父类写好了过程的方法,方法是抽象的,子类在用的时候复写
    这样父类就是一个模板,一个框架。

7   编写自己的类加载器
    知识讲解:
        自定义的类加载器的必须继承ClassLoader
        loadClass方法与findClass方法
        defineClass方法
    编程步骤:
        编写一个对文件内容进行简单加密的程序。
        编写了一个自己的类装载器,可实现对加密过的类进行装载和解密。
        编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,
    还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。
    实验步骤:
        对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如: java MyClassLoader MyTest.class F:\itcast
        运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast
        用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败。
        删除CLASSPATH环境下的类文件,再执行上一步操作就没问题了。

 代码部分:
 import java.io.*;
import java.lang.reflect.*;
public class MyClassLoader extends ClassLoader
{
 //加载类解密文件
 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 Class findClass(String name) //throws Exception //为什么不能抛出?因为如果没找到到这个类,需要告知调用者
 {
  try
  {
   File f = new File(path,name.substring(name.lastIndexOf('.')+1) + ".class");
   FileInputStream fis = new FileInputStream(f);
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   cypher(fis,bos);
   byte [] buf = bos.toByteArray();
   fis.close();
   bos.close();
   return defineClass(name,buf,0,buf.length);
  }catch(Exception e)
  {
   throw new ClassNotFoundException(name + " is not found!");
  }
  return null;
 }

 //对不带包名的class文件进行加密
 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);
  }
 }

 public static void main(String [] args) throws Exception
 {

  //下面省略了错误检查
  if(!args[0].endsWith("class"))
  {
   ClassLoader loader = new MyClassLoader(args[1]);
   Class cls = loader.loadClass(args[0]);
   
   /*
   让自定义类继承Date类
   System.out.println(cls.getClassLoader().getClass().getName());
    java.util.Date d = (java.util.Date)cls.newInstance();
    System.out.println(d.toString());
    */
    
   Method m = cls.getMethod("test");
   //m.invoke(cls.newInstance(),null);
   m.invoke(cls.newInstance());
   //((Test)cls.newInstance()).test();
   return;
  }
  else
  {  
   FileInputStream fis = new FileInputStream(args[0]);  
   File f = new File(args[1], new File(args[0]).getName());//不用检查目录最后是否有目录分割符
   FileOutputStream fos = new FileOutputStream(f);  
   cypher(fis,fos);
   fis.close();
   fos.close();
  }
 }
}

//类加载器不能加载这种非public的类
/*
Exception in thread "main" java.lang.IllegalAccessException: Class MyClassLoader
 can not access a member of class MyTest with modifiers ""
*/
/*
class MyTest
{
 public void test()
 {
  System.out.println("hello,www.it315.org");
 }
}
*/


 

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值