美文网首页
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)结论

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

相关文章

  • 热修复原理拆解个人笔记(一)

    源于sophix文档: 内部类/外部类java编译器对内部类的处理 匿名内部类匿名内部类 类加载类加载时间 fin...

  • Java如何加载一个外部类

    1.学习javapoet 文档 2.学习java类加载相关知识 (1)使用javapoet相关api 生成一个类...

  • (java知识小总结二)2018-05-31

    5.2Java 中的静态内部类:静态内部类是 static 修饰的内部类 特点:(1)、 静态内部类不能直接访问外...

  • 内部类

    慎用内部类 所谓内部类就是在一个类内部进行其他类结构的嵌套操作 Java内部类的定义、如何创建内部类、内部类的分类...

  • 单例模式

    关于内部类和静态内部类何时被加载:加载一个类时,其内部类是否同时被加载?静态内部类单例模式 结论:最好的单例模式是...

  • Service Provider Interface(SPI)

    Service Provider Interface SPI类加载 SPI是Java提供的一种加载外部类或者是第三...

  • java静态内部类的加载顺序和内部类单例模式

    java静态内部类的加载顺序:https://www.cnblogs.com/maohuidong/p/78438...

  • Java Lambda 和 Kotlin Lambda 的区别

    Java 匿名内部类在编译时会创建一个 class ,增加类的加载开销,运行时该内部类无论是否用到外部参数每次都会...

  • [Kotlin] 内部类

    内部类也叫做嵌套类,在Java里是一个被大家经常使用到的东西。内部类除了匿名内部类外还分为三种,一种是可以自由访问...

  • Java内部类

    Java内部类 大纲: java内部类有什么特点?为什么需要内部类? 非静态内部类持有外部类的引用 内部类的分类。...

网友评论

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

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