zoukankan      html  css  js  c++  java
  • 类加载机制的学习3___自定义的类加载器

        在程序中实现一个自定的类加载器:继承ClassLoader抽象类,重写findClass()。 如下位一个实例代码:

    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.Channels;
    import java.nio.channels.FileChannel;
    import java.nio.channels.WritableByteChannel;
    
    public class MyClassLoaderTest extends ClassLoader{
    
        private String filePath; //文件路径
        private String className; //类名
    
        public MyClassLoaderTest(String filePath,String className){
            this.filePath=filePath;
            this.className=className;
        }
    
        //获得被加载的类名
        public String getClassName(){
            return className;
        }
    
        @Override
        protected Class<?> findClass(String s) throws ClassNotFoundException {
    
            File file = new File(filePath+className+".class");
    
            try {
                //将字节码文件转化成字节数组
                byte[] classBytes = getClassBytes(file);
    
                //采用defineClass()方法将字节数组转化成class对象实例
                Class<?> aClass = defineClass(s, classBytes, 0, classBytes.length);
                return aClass;
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            //交给超类加载器进行加载
            return super.findClass(s);
        }
    
        //将字节码文件转化成字节数组
        public byte[] getClassBytes(File file) throws IOException {
            //文件输入流  读取文件
            FileInputStream fileInputStream = new FileInputStream(file);
    
            //文件通道 read(byteBuffer)  获得缓冲区中的数据
            FileChannel channel = fileInputStream.getChannel();
    
            //字节数组 toByteArray()  将输出流中的数据转换成一个字节数组
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    
            //可写的字节管道
            WritableByteChannel writableByteChannel = Channels.newChannel(byteArrayOutputStream);
    
            //申请一个字节缓存大小
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    
            //具体操作
            while(true){
                try {
                    int i = channel.read(byteBuffer); //从该通道获取到给定缓冲区的字节数列
                    if(i==0 || i==-1){
                        break;
                    }
                    byteBuffer.flip();
                    writableByteChannel.write(byteBuffer);
                    byteBuffer.clear();
    
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            fileInputStream.close();
            return byteArrayOutputStream.toByteArray();//将输出数据转换成字节数组
        }
    
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    
            MyClassLoaderTest loaderTest = new MyClassLoaderTest("D:/","People");
    
            //使用给定的类加载器对目标类进行加载  Class.forName(...) 进行手动加载
            Class<?> peopleClass = Class.forName(loaderTest.getClassName(), true, loaderTest);
    
            //通过反射从class对象来获得类的对象实例
            Object p = peopleClass.newInstance();
    
            System.out.println(p);
    
            //通过class对象实例,来获得具体的类加载器
            System.out.println(p.getClass().getClassLoader());
    
        }
    }

    输出结果:

    I am a people, my name is null
    MyClassLoaderTest@1540e19d

    总结:

    1.为什么要自定义类的加载器???

    通过自定义的类加载器,我们可以进行一些额外的操作,比如可以对字节码文件进行加密,解密。这就保护了原始字节码的安全性问题。

    2.为什么要使用双亲委派机制,进行类的加载???

    采用双亲委派机制,保证了类加载的全局唯一性,比如,java.lang.String 类是由启动类加载器(Bootstrap ClassLoader)进行加载的,当用户自定义一个String时,若不采用双亲委派机制,AppClassLoader就也会对用户自定义的String类进行加载,这就会使得Java体系类的原生类遭到破坏。

  • 相关阅读:
    批处理 windows service 的安装与删除
    HTML 页面元素介绍
    六 redis学习笔记之发布订阅
    发布个c#版的HandlerSocket客户端类库
    数据库单元测试
    一 redis学习笔记之环境搭建
    七 redis学习笔记之持久化
    三 redis学习笔记之排序
    四 redis学习笔记之事务
    元数据编程实战_使用Emit运行时生成Protobuf编码类
  • 原文地址:https://www.cnblogs.com/xbfchder/p/11412674.html
Copyright © 2011-2022 走看看