Java编译器——javac.exe

来源:互联网 发布:centos7 打开端口 编辑:程序博客网 时间:2024/05/21 19:12

一、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]

0 0
原创粉丝点击