码迷,mamicode.com
首页 > 编程语言 > 详细

Java千百问_08JDK详解(008)_通过代码如何编译java文件

时间:2016-06-19 07:53:59      阅读:318      评论:0      收藏:0      [点我收藏+]

标签:

点击进入_更多_Java千百问

1、通过代码如何编译java文件

编译器是一个命令行工具(jdk自带的编译工具javac,了解javac看这里:javac是什么),但也可以使用API来调用(一般的IDE都会使用这一组API来封装自己的编译功能)。编译器遵循Java语言规范(The Java Language Specification,JLS)和Java虚拟机规范(The Java Virtual Machine Specification,JVMS)。
在Java 6之后,提供了标准包来操作Java编译器,这就是javax.tools包。我们使用这个包中的API以及其他辅助包可以定制自己的编译器。通过ToolProvider类的源码我们可以看到,javax.tools这个包中的API最终都是通过tools.jar中的com.sun.tools.javac包来调用Java编译器的。

通过代码编译java大体有如下三种方式,灵活运用这几种方式可以DIY属于自己的编译器:

通过JavaCompiler.run()
最简单的用法即使用JavaCompiler类的run方法,前3个参数分别为:输入信息输出信息错误信息,如果为null则默认为:System.inSystem.outSystem.err。最后一个参数为javac后的命令文本,例如传入Test.java,则等同于在终端执行javac Test.java

例如:

public class Test {
 public static void main(String[] args) throws Exception {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int run = compiler.run(null, null, null, "-version");
        System.out.println("===" + run);
    }
}

执行结果(由于输出信息没有指定,默认打印在System.out中):

javac 1.7.0_79
===0

通过JavaCompiler.getTask()编译硬盘中代码
使用JavaCompiler.run方法非常简单,但它确不能更有效地得到我们所需要的信息。一般来说我们都会使用StandardJavaFileManager类(jdk 6或以上),这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener(监听)的实现。

具体实例如下:

public class Test {
public static void main(String[] args) throws Exception {
        Test.compiler();
}

public static void compiler() throws IOException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 建立DiagnosticCollector对象

        DiagnosticCollector diagnostics = new DiagnosticCollector();

        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);

        // 建立源文件对象,每个文件被保存在一个从JavaFileObject继承的类中
        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromStrings(Arrays
                .asList("/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/Test.java"));

        // options命令行选项
        Iterable<String> options = Arrays.asList("-d",
                "/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/classes");// 指定的路径一定要存在,javac不会自己创建文件夹
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null,
                compilationUnits);

        // 编译源程序
        boolean success = task.call();
        fileManager.close();
        System.out.println((success) ? "编译成功" : "编译失败");

        // 打印信息
        for (Object object : diagnostics.getDiagnostics()) {
            Diagnostic diagnostic = (Diagnostic) object;
            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));
        }
}
}

运行结果如下:

编译成功

在对应路径下会发现com/test/Test.class文件(Test的包是package com.test,所以会自动在对应目录下生成com/test/路径)。

通过JavaCompiler .getTask()编译内存中代码
JavaCompiler不仅可以编译硬盘上的Java文件,而且还可以编译内存中的Java代码,然后使用reflection来运行它们。我们可以编写一个JavaSourceFromString类,通过这个类可以输入Java源代码

具体实例如下:

public class Test {

    public static void main(String[] args) throws Exception {
        Test.compiler2();
    }
?public static void compiler2() throws IOException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        DiagnosticCollector diagnostics = new DiagnosticCollector();

        // 定义一个StringWriter类,用于写Java程序
        StringWriter writer = new StringWriter();
        PrintWriter out = new PrintWriter(writer);
        // 开始写Java程序
        out.println("public class HelloWorld {");
        out.println(" public static void main(String args[]) {");
        out.println(" System.out.println(\"Hello, World\");");
        out.println(" }");
        out.println("}");
        out.close();

        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
        // 为这段代码取个名子:HelloWorld
        SimpleJavaFileObject file = (new Test()).new JavaSourceFromString("HelloWorld", writer.toString());
        Iterable compilationUnits = Arrays.asList(file);
        // options命令行选项
        Iterable<String> options = Arrays.asList("-d",
                "/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/classes");// 指定的路径一定要存在,javac不会自己创建文件夹
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null,
                compilationUnits);

        boolean success = task.call();
        System.out.println((success) ? "编译成功" : "编译失败");
    }

    // 用于传递源程序的JavaSourceFromString类
    class JavaSourceFromString extends SimpleJavaFileObject {

        final String code;

        JavaSourceFromString(String name, String code) {
            super(URI.create("string:///" + name.replace(‘.‘, ‘/‘) + Kind.SOURCE.extension), Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return code;
        }
    }
}

运行结果如下:

编译成功

在对应路径下会发现HelloWorld.class文件。

Java千百问_08JDK详解(008)_通过代码如何编译java文件

标签:

原文地址:http://blog.csdn.net/ooppookid/article/details/51710981

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!