zoukankan      html  css  js  c++  java
  • java 类加载器的委托机制

    l 当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

    1.首先当前线程的类加载器去加载线程中的第一个类。

    2.如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。

    3.还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

    l 每个类加载器加载类时,又先委托给其上级类加载器。

    1.当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

    2.对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。

    每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类装载器去加载类,这就是类加载器的委托模式。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。

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

    把先前编写的类加入到jdk的rt.jar中,会有怎样的效果呢?不行!!!看来是不能随意将自己的class文件加入进rt.jar文件中的。

    编写自己的类加载器(需要再仔细看一遍,不是太懂)

    知识讲解:

    自定义的类加载器的必须继承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; 

        } 

         

        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",null);//在jdk1.5中报警告,为什么? 

                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"); 

        } 

    */ 

  • 相关阅读:
    使用Swagger为ASP.NET Core WebApi生成API文档
    TypeScript入门笔记(五)
    TypeScript入门笔记(四)
    TypeScript入门笔记(三)
    .net core WebAPI+EF 动态接收前台json,并动态修改数据库
    记走出自动化部署的第一步
    工厂模式
    使用bootstrap fileinput多文件拖拽上传的记录
    判断登录跳回原地址方法
    使用Microsoft Teams 搭建远程视频
  • 原文地址:https://www.cnblogs.com/fanweisheng/p/11137852.html
Copyright © 2011-2022 走看看