像Eclipse等java IDE是怎么编译和查找java源代码的呢?

源代码保存

这个无需多说,在编译器写入代码,并保存到文件。这个利用流来实现。

编译为class文件

java提供了JavaCompiler,我们可以通过它来编译java源文件为class文件。

查找class

可以通过Class.forName(fullClassPath)或自定义类加载器来实现。

生成对象,并调用对象方法

通过上面一个查找class,得到Class对象后,可以通过newInstance()或构造器的newInstance()得到对象。然后得到Method,最后调用方法,传入相关参数即可。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class MyIDE {

public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 定义java代码,并保存到文件(Test.java)
StringBuilder sb = new StringBuilder();
sb.append("package com.tommy.core.test.reflect;\n");
sb.append("public class Test {\n");
sb.append(" private String name;\n");
sb.append(" public Test(String name){\n");
sb.append(" this.name = name;\n");
sb.append(" System.out.println(\"hello,my name is \" + name);\n");
sb.append(" }\n");
sb.append(" public String sayHello(String name) {\n");
sb.append(" return \"hello,\" + name;\n");
sb.append(" }\n");
sb.append("}\n");

System.out.println(sb.toString());

String baseOutputDir = "F:\\output\\classes\\";
String baseDir = baseOutputDir + "com\\tommy\\core\\test\\reflect\\";
String targetJavaOutputPath = baseDir + "Test.java";
// 保存为java文件
FileWriter fileWriter = new FileWriter(targetJavaOutputPath);
fileWriter.write(sb.toString());
fileWriter.flush();
fileWriter.close();

// 编译为class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null,null,null);
List<File> files = new ArrayList<>();
files.add(new File(targetJavaOutputPath));
Iterable compilationUnits = manager.getJavaFileObjectsFromFiles(files);

// 编译
// 设置编译选项,配置class文件输出路径
Iterable<String> options = Arrays.asList("-d",baseOutputDir);
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, options, null, compilationUnits);
// 执行编译任务
task.call();


// 通过反射得到对象
// Class clazz = Class.forName("com.tommy.core.test.reflect.Test");
// 使用自定义的类加载器加载class
Class clazz = new MyClassLoader(baseOutputDir).loadClass("com.tommy.core.test.reflect.Test");
// 得到构造器
Constructor constructor = clazz.getConstructor(String.class);
// 通过构造器new一个对象
Object test = constructor.newInstance("jack.tsing");
// 得到sayHello方法
Method method = clazz.getMethod("sayHello", String.class);
// 调用sayHello方法
String result = (String) method.invoke(test, "jack.ma");
System.out.println(result);
}
}

自定义类加载器代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class MyClassLoader extends ClassLoader {
private String baseDir;
public MyClassLoader(String baseDir) {
this.baseDir = baseDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String fullClassFilePath = this.baseDir + name.replace("\\.","/") + ".class";
File classFilePath = new File(fullClassFilePath);
if (classFilePath.exists()) {
FileInputStream fileInputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
fileInputStream = new FileInputStream(classFilePath);
byte[] data = new byte[1024];
int len = -1;
byteArrayOutputStream = new ByteArrayOutputStream();
while ((len = fileInputStream.read(data)) != -1) {
byteArrayOutputStream.write(data,0,len);
}

return defineClass(name,byteArrayOutputStream.toByteArray(),0,byteArrayOutputStream.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != fileInputStream) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if (null != byteArrayOutputStream) {
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return super.findClass(name);
}
}

java源文件和编译后的class文件如下:

关于类的加载器可以参考:http://tommy88.top/2018/04/11/java-classloader/