美文网首页
Java如何加载一个外部类

Java如何加载一个外部类

作者: 我家造地球 | 来源:发表于2019-04-07 23:17 被阅读0次
    • 1.学习javapoet 文档
    • 2.学习java类加载相关知识

    (1)使用javapoet相关api 生成一个类

    public class CreateJavaFile {
        public static void main(String[] args) throws IOException {
            
            //生成一个方法体(main)  打印输出一个hello
            MethodSpec methodSpec = MethodSpec.methodBuilder("main")
                    .addModifiers(Modifier.PUBLIC,Modifier.STATIC)
                    .returns(void.class)
                    .addParameter(String[].class,"args")
                    .addStatement("System.out.println($S)","hello")
                    .build();
            
            //类相关操作
            TypeSpec typeSpec = TypeSpec.classBuilder("HelloWorld")
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(methodSpec)//添加一个方法体
                    .build();
            
            //包名操作
            JavaFile javaFile = JavaFile.builder("com.demo.helloworld",typeSpec).build();
            
            //输出代码到控制台
            javaFile.writeTo(System.out);
            
            //把代码生成到项目根目录 文件名为hello
            javaFile.writeTo(new File("hello"));
        }
    }
    

    执行完后,得到如下图。

    hello.png

    (2)新建一个classLoad类继承URLClassLoader

    
    public class MyClassLoad extends URLClassLoader {
        public MyClassLoad(URL[] urls) {
            super(urls);
        }
    
        @Override
        public Class<?> loadClass(java.lang.String name) throws ClassNotFoundException {
            System.out.println("loadClass--->"+name);
            return super.loadClass(name);
        }
    
        @Override
        protected Class<?> findClass(java.lang.String name) throws ClassNotFoundException {
            System.out.println("findClass--->"+name);
            return super.findClass(name);
        }
    }
    
    

    (3)测试,加载我们生成类,并调用方法

    public class TestLoadLocalClass {
        public static void main(String[] args) throws Exception {
    
            File file = new File("hello");
    
            URL url = file.toURL();
            
            //file.toURL() 方法过时可使用 如下代替
            //URL url = new URL("file:"+file.getAbsolutePath().replace("\\","/")+"/");
    
            MyClassLoad myClassLoad = new MyClassLoad(new URL[]{url});
            
            //加载类文件,包名+类名  
            //只能加载class文件  我们生成的.java文件 需要用 javac 手动转换一下
            Class aClass = myClassLoad.loadClass("com.demo.helloworld.HelloWorld");
    
            System.out.println(aClass.getClassLoader());
            
            //使用反射得到一个对象
            Object aObject = aClass.newInstance();
            
            //获取到main方法,方法的参数类型、个数一定要相匹配
            Method method = aClass.getMethod("main", String[].class);
    
            //执行main方法        
            method.invoke(aObject, new Object[]{new String[]{}});
        }
    }
    

    查看classLoad的打印日志,加载类到时候,是先执行loadClass 后执findClass

    loadClass--->com.demo.helloworld.HelloWorld
    findClass--->com.demo.helloworld.HelloWorld
    loadClass--->java.lang.Object
    MyClassLoad@12a3a380 //我们自己建的类加载器
    loadClass--->java.lang.String
    loadClass--->java.lang.System
    loadClass--->java.io.PrintStream
    hello  //输出类hello
    

    Java语言系统自带有三个类加载器:

    • BootstrapClassLoader 最顶层的加载类,主要加载核心类库
    • ExtentionClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。
    • AppclassLoader也称为SystemAppClass 加载当前应用的classpath的所有类。

    (4)进入ClassLoader.java 从源码看java类加载机制

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                // 首先,检查类是否已经加载
                Class<?> c = findLoadedClass(name);
                
                //如果类没有被加载过,如果加载过直接返回类,否则先使用父加载加载
                if (c == null) {
                    try {
                        //如果父加载器不为空则先使用父加载器
                        //否则使用引导类加载器
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        //抛出ClassNotFoundException异常
                    }
                    
                    //如果父加载器没有找到,则使用调用自身的findClass
                    //我们使用的是URLClassLoader,有兴趣的话,可以去查看URLClassLoader的findClass()方法
                    if (c == null) {
                        c = findClass(name);
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                //返回我们要使用到类
                return c;
            }
        }
    

    (5)结论

    类加载先从父加载器加载,父类没有加载到,则使用自身的加载器加载。

    相关文章

      网友评论

          本文标题:Java如何加载一个外部类

          本文链接:https://www.haomeiwen.com/subject/foisiqtx.html