Java编译器——javac.exe

一、javac.exe简介

javac.exe是java语言编译器。javac读取由java语言编写的类和接口的定义,并将它们编译成字节代码的class文件。

注意:

  • javac.exe使用Java语言编写的,而不是C语言,至于如何将Java程序封装为.exe文件,可以参考下面的博客:
    http://blog.csdn.net/kevinzhangfei/article/details/4569170
  • javac.exe包括在JDK里面,但不是JVM中的内容,JVM只负责执行.class文件,而javac.exe负责将java文件编译为class文件。

二、源码下载

OpenJDK6源码: http://download.java.net/openjdk/jdk6/
Javac的源码就在OpenJDK源码里面。
或者在CSDN下载: http://download.csdn.net/detail/p_3er/7383741
通过源码可以看到,javac其实就是一个java project。

三、javac中的包简介

将javac导入Eclipse,目录结构如下:
这里写图片描述
Javac的公共入口点是com.sun.tools.javac.main.Main。

  • com.sun.tools.javac.code
    描述java语言内在语义的类 – 类型types, 符号symbols等。
  • com.sun.tools.javac.comp
    用语义细节来分析和标注语法分析树, 比如确定标识符identifiers的类型和符号。
  • com.sun.tools.javac.jvm
    用于读写class files的后端类。
  • com.sun.tools.javac.main
    顶层的驱动类. 编译器的标准入口点是 com.sun.tools.javac.main.Main (more…)
  • com.sun.tools.javac.parser
    读取java源文件并创建语法分析树的类。
  • com.sun.tools.javac.resources
    编译器产生的资源文件. 其中两个是由”属性文件编译器”从属性源文件中生成的。Compiler.properties and javac.properties; 第三个是在构建的时候自动产生的,保存版本信息version.properties。
  • com.sun.tools.javac.tree
    表示java语言的被标注的语法树的类. 最顶层的节点Tree.TopLevel表示源文件的内容(应该是JCTree.TopLevel)。
  • com.sun.tools.javac.util
    工具类, 提供调试、文件系统存取和javac的集合类的支持。

四、javac.exe编译过程

这里写图片描述

Java源码编译机制

Java 源码编译由以下三个过程组成:

  1. 分析和输入到符号表
  2. 注解处理
  3. 语义分析和生成class文件

流程图如下所示:
这里写图片描述

最后生成的class文件由以下部分组成:

  1. 结构信息
    包括class文件格式版本号及各部分的数量与大小的信息。
  2. 元数据
    对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与方法声明信息和常量池。
  3. 方法信息
    对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息。

五、使用javac.exe的一些细节

1、如果一个java源文件有package选项,比如

package com.ghs;
public class Test{

}

(1)执行javac Test.java命令,会在当前目录生成一个Test.class文件,不会创建..\com\ghs目录。
(2)执行javac –d . Test.java命令,会在当前目录创建子目录com\ghs,生成的Test.class文件在ghs目录中。

javac命令的-d选项的本义是指定存放生成的类文件的位置;它还有一个作用,就是如果java源文件中有包名,那么-d选项告诉编译器,把生成的类文件放入反映包名的子目录中去,必要时创建目录。

2、import
import的作用是简化书写,在编译的时候,编译器会帮助我们把类的全名补上来,import的功能就到这了,它并不会把别的文件的代码写进来。
所以说import和#include是不一样的,#include会把别的文件的内容导入进来,而import不会,import只是简化了我们的书写。

3、java的package 机制
基本原则:需要将类文件切实安置到其所归属之Package所对应的相对路径下。
例如:以下面程序为例:假设此Hello.java文件在D:\Java\下

package  A;
public class Hello{
  public static void main(String args[]){   
     System.out.println("Hello World!");
  }
}
D:\Java>javac  Hello.java  此程序可以编译通过。
D:\Java>java  Hello       但是执行时,却提示以下错误!
Exception in thread "main" java.lang.NoClassDefFoundError: hello (wrong name: A/Hello)
        at java.lang.ClassLoader.defineClass0(Native Method)

原因是我们把生成的Hello.class规定打包在D:\Java\A文件中,必须在A文件中才能去运行。所以应该在D:\Java目录下建立一个A目录,然后把把Hello.class放在它下面,执行时,可正常通过!
D:\Java>java A.hello 就会输出:Hello world!
(就算是进入A目录下,运行java Hello命令,也会提示找不到类,因为带包名的类,在运行时必须指定包名,即java 命名后面跟的是类的完全限定名)

4、我用的是jdk1.6。但我没有配置classpath环境变量。在运行javac命令的时候,这个版本的jdk会自动在下面的目录中寻找类。
这是我的源文件:

package com.ghs;
public class Test{
    public static void main(String[] args){
        System.out.println("hello");
    }
}

比如我运行javac命令的时候,加上-verbose选项:
[search path for source files: .](默认会在当前路径下寻找java源文件)
[search path for class files: ](默认会在以下路径中寻找java源文件中用到的其它类的类文件,注意,这些路径都是在jdk中的jre目录下)
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\resources.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\rt.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\sunrsasign.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\jsse.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\jce.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\charsets.jar
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\modules\jdk.boot.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\classes,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\ext\dnsns.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\ext\localedata.jar,
C:\jdk-1.6-64\jdk1.6.0_37\jre\lib\ext\sunjce_provider.jar,
.(默认也会在当前路径中寻找)
]
[loading java\lang\Object.class(java\lang:Object.class)](load的类是在我写的java源文件中需要用的类;
还有一种情况,比如import 类名,那么这个类会被加载(就算是代码中没有用到);但是import 包名.*,这个包下面的类只有在代码中出现才会被加载。)
[loading java\lang\String.class(java\lang:String.class)]
[checking com.dyc.Test]
[loading java\lang\System.class(java\lang:System.class)]
[loading java\io\PrintStream.class(java\io:PrintStream.class)]
[loading java\io\FilterOutputStream.class(java\io:FilterOutputStream.class)]
[loading java\io\OutputStream.class(java\io:OutputStream.class)]
[wrote Test.class]

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: java.exejavac.exeJava开发工具中的两个不同的程序。 java.exeJava虚拟机(JVM)的执行程序,它负责解释和执行Java程序的字节码。当我们在命令行中输入"java xxx"时,就是在调用java.exe来执行xxx.class文件。 而javac.exeJava编译器的执行程序,它负责将Java源代码编译成字节码文件(.class文件)。当我们在命令行中输入"javac xxx.java"时,就是在调用javac.exe来将xxx.java文件编译成xxx.class文件。 因此,java.exejavac.exe的主要区别在于它们的功能不同,一个是执行Java程序,一个是编译Java程序。 ### 回答2: Java是跨平台的高级编程语言,它可以让开发人员创建各种类型的应用程序,从简单的命令行工具到复杂的企业级Web应用程序。 Java的代码是由Java编译器编译成Java字节码,这些字节码由Java虚拟机(JVM)解释执行。Java编译器由两个主要组件组成,即java.exejavac.exeJava.exe Java.exeJava虚拟机(JVM)的一部分。它是运行Java字节码的主要组件。当Java程序被编译并生成字节码文件后,它们必须由java.exe在JVM上运行。 Java.exe可以通过命令行启动,也可以在Web浏览器中作为Java插件运行。在命令行中,可以使用以下命令启动Java虚拟机: java [options] classname [args] 其中,[options]是可选项,用于指定Java虚拟机的运行参数。classname是要运行的Java类的名称。[args]是传递给Java类的参数列表。 Javac.exe Javac.exeJava编译器的一部分。它用于将Java源代码编译成Java字节码。Javac.exe从.java源代码文件中读取代码,然后将其编译成Java字节码。这些字节码可以由java.exe在JVM上执行。 在命令行中,可以使用以下命令来编译Java源代码: javac [options] filename.java 其中,[options]是可选项,用于指定编译器的选项和参数。filename.java是要编译的Java源代码文件的名称。 总结: Java.exeJavac.exe都是Java的重要组件。Java.exeJava虚拟机的一部分,它负责在JVM上运行Java字节码。而Javac.exeJava编译器的一部分,用于将Java源代码编译成Java字节码。Java程序必须首先使用Javac.exeJava源代码编译成字节码,然后再使用Java.exe在JVM上运行它们。 ### 回答3: java.exejavac.exeJava语言中两个非常重要的执行程序,它们的主要区别体现在针对不同的Java源文件进行编译和执行。 首先,java.exeJava的运行程序,可以说是Java虚拟机(JVM)的启动器。当开发者编写一个复杂的Java程序之后,需要把这个程序编译成一个字节码文件,格式为“.class”文件。然后,通过利用java.exe启动JVM,让字节码文件能够被JVM识别并完成程序的执行。也就是说,java.exe主要负责加载和执行已编译的Java程序。 而javac.exe则是Java开发者使用的编译器,它可以将源代码编译成为字节码文件,生成后缀为“.class”的可执行文件。也就是说,开发者编写的Java源代码,在使用了javac编译器之后,可以被转化为可在Java虚拟机上执行的格式化指令。因此,javac主要负责编译Java程序源代码,生成可以被java.exe启动的字节码文件。 另外,需要说明的是,java.exejavac.exe属于Java Development Kit(JDK)中的组件,是Java开发的必要组成部分。从本质上来说,它们是Java开发中不可或缺的两个程序执行器,能够实现程序的编译和运行。 总而言之,java.exejavac.exe虽然在名字上非常相似,但是它们的功能和作用却存在很大的区别。java.exeJava运行时的启动程序,用于加载和执行已编译的Java程序;而javac.exeJava开发者主要使用的编译器,用于将Java源代码编译成可以在Java虚拟机上执行的字节码文件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值