• Java类加载机制


    Java类加载机制;

    为啥叫双亲委派?爹妈分别是谁?

    The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.

    jdk中根本没说爹妈的事情,就是一个delegation的事情,

    delegation
    英[ˌdelɪˈgeɪʃn]
    美[ˌdɛlɪˈɡeʃən]
    n.	授权; 委派; 代表(团);

    bootstrap - jre/lib/rt.jar

    extclassLoader-jre/lib/ext/*.jar

    appClassLoader-classpath指定

    myClassLoader-自己指定的;

    学习了:http://blog.csdn.net/csh624366188/article/details/8096989 这个大神膜拜一下!

    http://blog.csdn.net/yangxin_blog/article/details/48214857 

    需要对程序做一点点修改,源码如下:

    package com.stono.jvm;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    public class MyClassLoader extends ClassLoader {
        private String name; // 类加载器的名字
        private String path = "d:\"; // 加载类的路径
        private final String fileType = ".class"; // class文件的扩展名
        public MyClassLoader(String name){
            super(); // 让系统类加载器成为该类加载器的父加载器
            this.name = name;
        }
        public MyClassLoader(ClassLoader parent, String name){
            super(parent); // 显示指定该类加载器的父加载器
            this.name = name;
        }
        @Override
        public String toString() {
            return this.name;
        }
        public String getPath() {
            return path;
        }
        public void setPath(String path) {
            this.path = path;
        }
        /** 
         * @param 类文件的名字 
         * @return 类文件中类的class对象 
         *  
         * 在这里我们并不需要去显示的调用这里的findclass方法,在上篇文章中,我们通过查看 
         * loadclass的源码可以发现,她是在loadclass中被调用的,所以这里我们只需重写这个方法, 
         * 让它根据我们的想法去查找类文件就ok,他会自动被调用 
         *  
         *  
         * defineClass()将一个 byte 数组转换为 Class 类的实例。必须分析 Class,然后才能使用它 
         * 参数: 
             * name - 所需要的类的二进制名称,如果不知道此名称,则该参数为 null 
             * b - 组成类数据的字节。off 与 off+len-1 之间的字节应该具有《Java Virtual Machine Specification》定义的有效类文件的格式。 
             * off - 类数据的 b 中的起始偏移量 
             * len - 类数据的长度  
         */  
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] data = this.loadClassData(name); // 获得类文件的字节数组
            return this.defineClass(name, data, 0, data.length);
        }
        /** 
         *  
         * @param 类文件的名字 
         * @return 类文件的 字节数组 
         * 通过类文件的名字获得类文件的字节数组,其实主要就是用 
         * 输入输出流实现。 
         */  
        private byte[] loadClassData(String name) {
            InputStream is = null;
            byte[] data = null;
            ByteArrayOutputStream baos = null;
            try {
                this.name = this.name.replace(".", "\");
                String replaceAll = name.replace(".", "\"); // 注意这块修改了一下
                is = new FileInputStream(new File(path+replaceAll+fileType)); 
                baos = new ByteArrayOutputStream();
                int ch = 0;
                while(-1!=(ch=is.read())){
                    baos.write(ch);
                }
                data = baos.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    is.close();
                    baos.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            return data;
        }
        
        public static void main(String[] args) throws Exception {
            MyClassLoader loader1 = new MyClassLoader("loader1");
            loader1.setPath("D:\myapp\serverlib\");
            MyClassLoader loader2 = new MyClassLoader(loader1, "loader2");
            loader2.setPath("D:\myapp\clientlib\");
            MyClassLoader loader3 = new MyClassLoader(null,"loader3");
            loader3.setPath("D:\myapp\otherlib\");
            test(loader1);
            System.out.println("-------------");
            test(loader2);
            System.out.println("-------------");
            test(loader3);
            Object object = loader2.loadClass("Simple").newInstance();
            System.out.println(object instanceof Simple);
            Object object1 = loader1.loadClass("com.stono.jvm.Simple").newInstance();
            System.out.println(object1 instanceof Simple); // true 了
            Object object2 = loader2.loadClass("com.stono.jvm.Simple").newInstance();
            System.out.println(object2 instanceof Simple); // true 了
            Object object3 = loader3.loadClass("com.stono.jvm.Simple").newInstance();
            System.out.println(object3 instanceof Simple); // false 了
        }
        private static void test(MyClassLoader loader) throws Exception {
            Class<?> clazz = loader.loadClass("com.stono.jvm.Simple");
            System.out.println(clazz.getClassLoader());
        }
    }

    直接重构com.stono.jvm.ClassLoaderTest.main(...).new ClassLoader() {...}.findClass(String)方法好像是没有效果,

    没有效果的源码如下:可能是jdk版本变了,当前使用了jdk1.8;

    package com.stono.jvm;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class ClassLoaderTest {
        public static void main(String[] args) throws Exception {
            // 匿名内部类实现自定义类加载器
            ClassLoader myClassLoader = new ClassLoader() {
                @Override
                protected Class<?> findClass(String name) throws ClassNotFoundException {
                    // 获取类文件名
                    String filename = name.substring(name.lastIndexOf("."+1))+".class";
                    InputStream in = getClass().getResourceAsStream(filename);
                    if(in == null){
                        throw new RuntimeException("Could not found class file:"+filename);
                    }
                    byte[] b = null;
                    try {
                        b = new byte[in.available()];
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return defineClass(name, b, 0,b.length);
                }
            };
            // 好像是自己定义的类加载机制,结果没有效果呀;
            Object obj = myClassLoader.loadClass("com.stono.jvm.ClassLoaderTest").newInstance();
            System.out.println(obj.getClass().getClassLoader());
            System.out.println(ClassLoaderTest.class.getClassLoader());
            System.out.println(obj instanceof ClassLoaderTest);
        }
    }

    学习了:http://blog.csdn.net/p10010/article/details/50448491

    由于不能引用默认包中的类,所以需要进行代包的文件的编写,稍微麻烦一些;

    不过可以通过自己定义的classLoader发现声明的类不是系统加载的类,!

  • 相关阅读:
    前端cookie操作用到的一些小总结
    sublime 官方正版,自己用的插件配置,最轻量级安装流程
    Node.js 终端输出颜色设置
    Mac中设置别名 (转载)
    Swift 3 使用objc_setAssociatedObject
    ruby 笔记
    编程模式
    rvm pod gem 等常用命令
    node.js 笔记
    Node.js 对象合并
  • 原文地址:https://www.cnblogs.com/stono/p/8214928.html
Copyright © 2020-2023  润新知