java 手动编译 .class文件

一、使用 javax.tools 包下面的ToolProvider.getSystemJavaCompiler() 方法,具体如下:

String path = "src/main/resources/templates";
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        int run = javaCompiler.run(null, null, null, "-d", path, "src/main/resources/templates/Hello.java");
        System.out.println(run);

run 方法中前三个参数为系统的输入、输出以及异常流,可直接设置为null,重点是后面三个,“-d” 指定编译到某文件夹下面,后可跟盘符,和-D有的区别在于-D是设置系统参数的,-d是设置指定文件目录的;第五个参数为指定编译后的class文件存放的位置(可跟盘符),第六个参数就是要编译的java文件路劲,注意,按照上述方法编译是不会出错的,如果报异常为:无效标记(后面是路劲),说明没有指定的文件夹,或者不存在该文件夹路劲即可;最后run返回的值为0时,说明编译成功。

另外看了好些个版本的,参数都不一样,比如:

compiler.run(null, null, null,"-encoding","UTF-8","-classpath", "src/main/resources/templates/","src/main/resources/templates/Hello.java");

"-encoding","UTF-8","-classpath"  ,其实这种方式和上面的都一样,-classpath是指定的编译后的class文件存放位置为当前java文件所在的位置,和上面的-d一个作用,但-d时存放在指定目录下, 这两种方式对于比如说有两个类(相互引用)、或者有其中一个类引用了另一个类,编译都会失败。

另外还有一种方式是使用Runtime执行javac命令的方式来编译Java代码如下:

String jarAbsolutePath = "src/main/resources/static/";//指定编译后的存放的class文件位置
		
String javaAbsolutePath = "src/main/resources/templates/Student.java";//需要编译的java文件
		Process process = Runtime.getRuntime().exec("javac -classpath " + jarAbsolutePath + " " + javaAbsolutePath);//-classpath位置可用-d来代替
		try {
			InputStream errorStream = process.getErrorStream();
			InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
			String line = null;
			while ((line = bufferedReader.readLine()) != null) {
				System.out.println(line);
			}
			int exitVal = process.waitFor();
			System.out.println("Process exitValue: " + exitVal);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

上述编译成功后会打印:Process exitValue: 0

如有乱码或者打印多行,说明编译失败,请仔细看看路劲是否正确。

但是这两中方式最终都不能解决方才说的两个类的引用编译问题,最后通过查阅多个资料,看到一种编译方式非常好用,直接代码:

//递归获取指定编译目录下的所有java文件并放入文件集合中
public static void compiler(File file, String targetPath, List<File> sourceFiles) {
		File targetDir = new File(targetPath);
		if (!targetDir.exists()) {
			targetDir.mkdirs();
		}
		if (file != null && file.exists()) {
			File[] listFiles = file.listFiles();
			if (null == listFiles || listFiles.length == 0) {
				return;
			}
			for (File file2 : listFiles) {
				if (file2.isDirectory()) {
					compiler(file2, targetPath, sourceFiles);
				} else {
					if (file2.getName().endsWith(".java")) {
						try {

							sourceFiles.add(file2);
						} catch (Exception e) {
							System.out.println("888888");// TODO: handle exception
						}
					}
				}
			}
		}
	}

    //编译java文件
	public static boolean compilerJavaFile(List<File> sourceFile, String targerPath) throws IOException{

		boolean flag = false;
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, null);
		Iterable<? extends JavaFileObject> javaFileObjectsFromFiles = fileManager
				.getJavaFileObjectsFromFiles(sourceFile);
		Iterable<String> options = Arrays.asList("-d", "src/main/resources/static/");
		flag = compiler.getTask(null, fileManager, diagnosticCollector, options, null, javaFileObjectsFromFiles).call();
		for (Diagnostic<? extends JavaFileObject> diagnostic : diagnosticCollector.getDiagnostics()) {
			System.out.printf(
					"Code: %s%n" + "Kind: %s%n" + "Position: %s%n" + "Start Position: %s%n" + "End Position: %s%n"
							+ "Source: %s%n" + "Message: %s%n",
					diagnostic.getCode(), diagnostic.getKind(), diagnostic.getPosition(), diagnostic.getStartPosition(),
					diagnostic.getEndPosition(), diagnostic.getSource(), diagnostic.getMessage(null));
		}
        fileManager.close();
		return flag;

	}


public static void main(String[] args) throws ClassNotFoundException, IOException {

		String targetPath = "src/main/resources/static/";

		// 源文件目录
		String sourcePath = "src/main/resources/templates/";
		File sourceFile = new File(sourcePath);
		List<File> sourceFiles = new ArrayList<File>();
		compiler(sourceFile, targetPath, sourceFiles);
		boolean result = compilerJavaFile(sourceFiles, targetPath);
		System.out.println("compiler finish!" + result);
}

想必上述代码中最难看懂的就属这段代码了:

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, null);
        Iterable<? extends JavaFileObject> javaFileObjectsFromFiles = fileManager
                .getJavaFileObjectsFromFiles(sourceFile);
        Iterable<String> options = Arrays.asList("-d", "src/main/resources/static/");
        flag = compiler.getTask(null, fileManager, diagnosticCollector, options, null, javaFileObjectsFromFiles).call();
        for (Diagnostic<? extends JavaFileObject> diagnostic : diagnosticCollector.getDiagnostics()) {
            System.out.printf(
                    "Code: %s%n" + "Kind: %s%n" + "Position: %s%n" + "Start Position: %s%n" + "End Position: %s%n"
                            + "Source: %s%n" + "Message: %s%n",
                    diagnostic.getCode(), diagnostic.getKind(), diagnostic.getPosition(), diagnostic.getStartPosition(),
                    diagnostic.getEndPosition(), diagnostic.getSource(), diagnostic.getMessage(null));
        }
使用StandardJavaFileManager类。这个类能非常好地控制输入、输出,并且能通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现;使用StandardJavaFileManager需要两步。首先建立一个DiagnosticCollector实例及通过JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。最后通过CompilationTask中的call方法编译源程式。 

CompilationTask getTask(Writer out,
                            JavaFileManager fileManager,
                            DiagnosticListener<? super JavaFileObject> diagnosticListener,
                            Iterable<String> options,
                            Iterable<String> classes,
                            Iterable<? extends JavaFileObject> compilationUnits);

  在使用这种方法调用Java编译时最复杂的方法就是getTask,下面让我们讨论一下getTask方法。这个方法有如下所示的6个参数:

这些参数大多数都可为null。他们的含义所下。 
o  ?out::用于输出错误的流,默认是System.err。 
o  ?fileManager::标准的文件管理。 
o  ?diagnosticListener: 编译器的默认行为。 
o  ?options: 编译器的选项 
o  ?classes:参和编译的class。 
  最后一个参数compilationUnits不能为null,因为这个对象保存了你想编译的Java文件。 
在使用完getTask后,需要通过StandardJavaFileManager的getJavaFileObjectsFromFiles或getJavaFileObjectsFromStrings方法得到compilationUnits对象

调用这两个方法的方式如下:.

Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
Iterable<? extends File> files)
Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(
Iterable<String> names)
String[] filenames = …;
Iterable<? extends JavaFileObject> compilationUnits =
fileManager.getJavaFileObjectsFromFiles(Arrays.asList(filenames));
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager,
diagnostics, options, null, compilationUnits);
该段代码解释来源于下文链接:
原文链接:https://blog.csdn.net/m_hahahaha1994/article/details/51657969

上述如有问题、意见,请看到的同僚指点提问,你的支持,是我动力所在,谢谢!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱墩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值