• java 自定义类加载器


    百度了一下,通篇全部都是启动类加载器,扩展类加载器,应用程序类加载器,还有就是双亲委托模式 。

    可是一圈下来,新手们依然不知道如何自定义一个类加载器,来生动的展现什么是类加载器。

    首先我们在E:upload下新建一个a/BB.java文件。

    代码如下:

    package a;
    
    public class BB {
        private String a;
        public BB(){
    
        }
        public BB(String a){
            this.a=a;
        }
        public static void main(String[] args) {
             System.out.println("aaaaaaaaaa");
        }
    
    }

      编译后出现BB.class字节码文件

    退回到上级目录,因为包是到a目录的。执行java a.BB;正确执行main方法

      

    现在我们回到IDea编辑器中,将BB.class文件读取到内存,并且利用反射进行实例化。

    自定义类加载器   MyClassLoader.java

    package a;
    
    import java.io.*;
    import java.lang.reflect.Field;
    
    public class MyClassLoader  extends ClassLoader{
        @Override
        protected Class<?> findClass(String name) {
            byte[] bytes=null;
            //将点替换成斜杠
            String fileName=name.replaceAll("\.","/");
            StringBuilder sb=new StringBuilder("E:");
            sb.append(File.separator);
            sb.append("upload");
            sb.append(File.separator);
            sb.append(fileName);
            sb.append(".class");
            fileName=sb.toString();
            try {
                InputStream is=new FileInputStream(fileName);
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                byte[] buf=new byte[1024];
                int r=0;
                while ((r=is.read(buf))!=-1){
                    bos.write(buf,0,r);
                }
                bytes=bos.toByteArray();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return defineClass(name,bytes,0,bytes.length);
        }
    
        public static void main(String[] args) throws Exception{
            //自定义类加载器对象1
            MyClassLoader c1=new MyClassLoader();
            String className="a.BB";
         //loadClass调用的就是findClass() Class clazz1
    =c1.loadClass(className); //自定义类加载器对象2 MyClassLoader c2=new MyClassLoader(); Class clazz2=c2.loadClass(className); System.out.println(clazz1.getClassLoader()); System.out.println(clazz2.getClassLoader()); if(clazz1!=clazz2){ System.out.println("不同的类加载器对象加载相同的class文件,会产生不同的类对象"); } Object obj1=clazz1.getDeclaredConstructor(new Class[]{String.class}).newInstance("自定义加载器加载进内存的"); Field fa=clazz1.getDeclaredField("a"); fa.setAccessible(true);//将私有变量设置成可以访问的权限 System.out.println(fa.get(obj1)); } }

    执行结果:

    e.MyClassLoader@2b193f2d
    e.MyClassLoader@4dc63996
    不同的类加载器加载相同的class文件,会产生不同的类对象
    自定义加载器加载进内存的

    很明显clazz1和clazz2是两个类。

    给BB.java中构造器传入的字符串:“自定义加载器加载进内存的”   也在上面打印出来了。

    注意:如果将a/BB.java文件拷贝到idea编辑器中。那么MyClassLoader中的findClass就不会执行了。

    因为MyClassLoader c1和MyClassLoader c2都继承自ClassLoader,所以直接交给上级类加载器加载应用程序类加载器:Application ClassLoader;

    应用程序类加载器会首先找到a/BB.class文件,并加入内存;此时就不会在继续x向下传播调用加载了。

    类加载器在加载的时候虚拟机会首先调用加载器的私用方法loadClassInternal()

     而这个方法唯一作用就是调用自己的loadClass()方法,如果loadClass()加载失败了,则会调用自己的findClass()。

    loadClass()也能被重写,但是我们不会这样做,因为这样做的话,所有的类都会走这个方法来加载类;那么虚拟机内置的一些类也会用这个方法里面的逻辑来加载,固定会报错。

     
  • 相关阅读:
    pixysoft.framework.messageflow enterprise edition 开发实录
    软件工程革命三部曲 — 系统开发分类与重用说明
    vs2010 premium版本 使用小结 更多是问题。。
    报表引擎终于做出来了!!!
    报表引擎终于做出来了!!!!!参考了根兄的文档。
    页面驱动开发(Page Driven) —— 一种大多数人还不认同的技术
    从SOA到云计算 我个人理解
    谈谈Exception,什么时候抛出?什么时候接住? 二
    软件工程革命三部曲 —— 系统开发的业务部分重构在思考。
    Pixysoft.Framework.Reports 开发实录
  • 原文地址:https://www.cnblogs.com/guoyansi19900907/p/12566101.html
Copyright © 2020-2023  润新知