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

点击进入_更多_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.in、System.out、System.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文件。

时间: 2024-10-26 16:40:08

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

Java千百问_08JDK详解(006)_jdk用户界面类库都有什么

点击进入_更多_Java千百问 1.jdk用户界面类库都有什么 了解java核心框架看这里:java核心框架是什么样的 1. 输入法框架(Input Method Framework) 输入法框架包括文本编辑组件与文本输入.文本输入是软件组件,使得用户输入文本而不是简单的在键盘上打字.它们通常用于输入日本.中国或韩国的语言,输入比键盘按键多出数百倍的文本.当然,框架还支持其他语言,以及完全不同的输入机制,如手写和语音识别. 了解更多输入法框架看这里:[java输入法框架是什么][3] 可接入性库

Java千百问_08JDK详解(003)_jdk基础类库都有什么

点击进入_更多_Java千百问 1.jdk基础类库都有什么 了解java核心框架看这里:java核心框架是什么样的 jdk基础类库分为两大部分,基础库.扩展基础库,提供了相当大量的功能,基础库具体如下: lang包.util包(Lang and Util Packages) lang包提供的基本Object类.Class类.String类.基本类型的包装类.基本的数学类等等最基本类. util包提供基本的集合框架.jar处理等基础类. 了解lang包.util包看这里:[lang包.util包有

Java千百问_08JDK详解(017)_Javadoc是什么

点击进入_更多_Java千百问 1.Javadoc是什么 javadoc是Sun公司提供的一个技术,它从程序源代码中抽取类.方法.成员等注释,形成一个和源代码配套的API帮助文档.也就是说,只要在编写程序时以一套特定的标签作注释,在程序编写完成后,通过Javadoc就可以形成开发文档了. 了解注释看这里:注释是什么 2.如何使用Javadoc java为javadoc技术独立出了一个工具,它位于JAVA_HOME/bin/路径中,在终端中执行如下命令: javadoc 文件名.java java

Java千百问_08JDK详解(016)_AttachAPI是什么

点击进入_更多_Java千百问 1.AttachAPI是什么 Attach API是Sun公司提供的一套扩展API,它并不是Java的标准API.顾名思义,Attach,为JVM附加某些程序.简单来说,就是把一个程序连接到一个正在运行的JVM上,连接之后,这段程序就可以在JVM中运行.这段程序被称为JVMTI Agent程序. 我们使用它可以很方便地在运行过程中动态地设置加载代理类(JVMTI Agent),使我们能方便的监控一个JVM,运行一个外加的代理程序. 了解JVMTI Agent看这里

Java千百问_08JDK详解(013)_JVMTI是什么

点击进入_更多_Java千百问 1.JVMTI是什么 JVMTI(JVM Tool Interface)是JPDA体系中的最底层, 由Java虚拟机提供的native编程接口,是JVMPI(Java Virtual Machine Profiler Interface)和 JVMDI(Java Virtual Machine Debug Interface)的更新版本. 了解JPDA体系看这里:JPDA是什么 从它的发展中我们就可以知道,JVMTI提供了调试(debug)和分析(profiler

Java千百问_08JDK详解(011)_jnlp文件是什么

点击进入_更多_Java千百问 1.jnlp文件是什么 JNLP(Java Network Launching Protocol ,java网络执行协议文件)是java提供的一种可以通过浏览器直接执行java应用程序的途径,它使你可以直接通过一个网页上的url链接打开一个java应用程序. Java桌面应用程序可以通过JNLP的方式发布.如果版本升级后,不需要再向所有用户发布版本,只需要更新服务器的版本,这就相当于让java应用程序有了web应用的优点.如果你使用JNLP打包一个应用程序,那么它

Java千百问_08JDK详解(010)_java、javaw、javaws有什么区别

点击进入_更多_Java千百问 1.java.javaw.javaws有什么区别 java.javaw.javaws这三个都是jdk自带的三个工具,都在jdk/bin路径下,这三个工具都是为了启动java应用存在的,具体区别如下: java java命令即java应用的执行器,通过它执行的应用日志会再控制台console显示输出与错误信息. 了解更多java命令看这里:java程序如何运行 javaw javaw与java一样,是java应用的执行器,不同的是它不会再控制台console显示输出

Java千百问_08JDK详解(003)_java核心框架是什么样的

点击进入_更多_Java千百问 1.jdk基础扩展类库都有什么 了解java核心框架看这里:java核心框架是什么样的 jdk基础类库分为两大部分,基础库.扩展基础库,提供了相当大量的功能,扩展基础库具体如下: I/O工具(I/O) java.io和java.nio包提供了一组非常丰富的api来管理应用程序的I/O(输入/输出).包括文件和设备I/O.对象序列化.缓冲区管理.字符集支持等.此外,API还为服务端提供了包括多路复用.非阻塞I/O.内存映射和文件锁等功能. 了解更多java.io和j

Java千百问_08JDK详解(018)_JConsole是什么

点击进入_更多_Java千百问 1.JConsole是什么 JConsole是一个Java程序性能分析器,可以从命令行或在终端中运行.可以用来监控Java程序的性能以及跟踪代码. 同时在com.sun.tools.jconsole包中提供了一组接口,允许访问JConsole,对线程.内存.类.对象进行分析和统计. 2.如何使用JConsole工具 我们这里主要介绍jconsole工具的用法,在JAVA_HOME/bin路径中,我们可以直接打开他.如下图: 我们可以对正在运行的本地进程或者远程进程