zoukankan      html  css  js  c++  java
  • ClassLoader

    什么是类加载器

    java类加载器是通过一个类的全限定名来获取描述此类的二进制字节流,来进行加载;

    加载器是在虚拟机外部实现的,方便让程序自己决定获取所需要的类。

    JAVA有哪些类加载器

     对于开发人员来说,java的类加载器有四种,全都继承自抽象类java.lang.ClassLoader:

    启动类加载器(Bootstrap ClassLoader)


    它是虚拟机的一部分,无法被Java程序直接引用,所以System.class.getClassLoader()结果为null;

    负责加载JAVA_HOMElib目录中规定的类库,例如rt.jar的java.lang.object等核心api。

    扩展类加载器(Extension ClassLoader)


     负责加载<JAVA_HOME>libext目录,可以被开发人员直接使用。

    程序类加载器(Application ClassLoader)


     程序默认的加载器,负责加载ClassPath下的类或jar,可以被开发人员直接使用。

    自定义类加载器


    自定义加载器需要继承ClassLoader,可以自己指定需要加载的类,以下是一个自定义加载器的demo:

    package classLoader;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * 自定义加载器测试类
     * 
     */
    public class TestClassLoader extends ClassLoader{
    
        public static void main(String[] args) throws Exception{
            
            MyclassLoader myclassLoader = new MyclassLoader();
            AObj aObj = (AObj)myclassLoader.loadClass("classLoader.AObj").newInstance();
            aObj.sayHello();
        }
    }
    
    
    /**
     * 自定义加载器类(需继承ClassLoader)
     */
    class MyclassLoader extends ClassLoader{
    
        
        /**
         * 自定义加载器有两种方式:
         *         重写findClass():此种方式遵守了双亲委派模式,符合java设计体系,推荐。
         *         重写loadClass():会破坏双亲委派模式,因为双亲委派的逻辑代码就在loadClass方法中,非不得已而为之。
         */
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            
            byte[] bt = loadClassData(name);
            
            //defineClass()是必须的,作用是通过class文件字节数组去获取Class对象
            return this.defineClass(name,bt,0,bt.length);
        }
    
        
        /**
         * 获取class的字节数组
         * @param name
         * @return
         */
        private byte[] loadClassData(String name) {
            
            String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
            InputStream is = getClass().getResourceAsStream(fileName);
            byte[] bt = null;
            
            
            try {
                
                
                bt = new byte[is.available()];
                is.read(bt);
                
                
            } catch (IOException e) {
                
                e.printStackTrace();
                
            }finally{
                
                
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            return bt;
        }
    }
    
    
    
    /**
     * 用于测试自定义加载器的对象
     */
    class AObj{
        
        public void sayHello() {
            
            System.out.println("Hello Word!");
        }
    }
    View Code

    需要注意的是,即使用自定义加载器也无法加载像java.lang开头这样的类;

    不过我并没有做此实验,因为实在是要去洗澡了。

    类加载器之间的关系

    启动类加载器 > 扩展类加载器 > 程序类加载器 >自定义类加载器:

    它们之间不是继承关系,而是通过组合实现的,而这种模型也被称为双亲委派,如下图:

    双亲委派模型

    概念


    双亲委派的代码逻辑在java.lang.ClassLoader.loadClass()中;

    他是说某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归;

    如果父类加载器可以完成类加载任务,就成功返回;

    只有父类加载器无法完成此加载任务时,才自己去加载。

    为什么使用双亲委派


    因为java的设计体系,比如继承,所有的类都必须继承object类,那就必须确定object是唯一的,否则我们怎么知道该继承哪个object;

    而双亲委派会把加载类递归交给上一层加载器去做,如果加载不了,就自己完成,这一确保了类在系统中的唯一性。

  • 相关阅读:
    【历史时刻】从学生到社会独立人——硕士毕业
    Linux 常用命令
    LInux系统下搭建redis集群
    docker 下创建自定义网络,并在运行容器时绑定网络和ip
    docker下安装mysql镜像
    windows下将consul注册为系统服务
    Sql批量替换字段字符,Sql批量替换多字段字符,Sql替换字符
    gerrit安装配置
    Linux安装jdk8及环境变量配置
    iTerm2配置优化
  • 原文地址:https://www.cnblogs.com/dahuandan/p/7112245.html
Copyright © 2011-2022 走看看