Java如何加载一个外部类
2019-04-07 本文已影响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)结论
类加载先从父加载器加载,父类没有加载到,则使用自身的加载器加载。