【总结】java命令解析以及编译器,虚拟机如何定位类

来源:互联网 发布:linux网络相关命令 编辑:程序博客网 时间:2024/06/06 02:03

【总结】java命令解析以及编译器,虚拟机如何定位类

 PS:本文转载自:http://hxraid.javaeye.com/blog/508123

文章分类:Java编程

      学Java有些日子了,一直都使用IDE来写程序。这样的好处就是能让我连如何用命令行编译,解释执行Java源代码都不知道,就更不清楚JDK中的编译器和虚拟机(包含字节码解释器)是如何定位到类文件的。悲哀呀.......


1、安装JDK,配置环境变量。

    不将JDK所在的目录配置到系统环境变量中,系统怎么能找到JDK中的编译器,解释器在哪呀?如果不指明JDK的bin文件夹的位置,在shell中是无法找到javac/java命令的。这点就不多说了。


2、编译,解释执行Java程序。【 javac命令/java命令】

    (1) Test.java源代码

Java代码
  1. <span style="font-size: small;">//缺省包,该程序源代所在位置: e:/project/ Test.java  
  2.   
  3. public class Test{  
  4.       .....  
  5.       public static void main(String[] args){  
  6.       .....  
  7.       }  
  8. } </span>  
//缺省包,该程序源代所在位置: e:/project/ Test.javapublic class Test{      .....      public static void main(String[] args){      .....      }} 

        编译命令:javace:/project/Test.java   在e:/project目录下生成了Test.class

       注意:如果想要将Test.class生成在指定目录下,可以使用javac -d命令,如javac-d c:/   e:/project/Test.java  在c:/目录下生成Test.class(即e:/Test.class)

               javac -cp 中的-cp并不是指定Test.java的目录,这一点不要误解了。-cp/-classpath只能是指定类文件(.class文件)的路径。上面的命令不能写成:  java -cp e:/project Test.java


      解释执行命令: 【java-cp e:/projectTest 将调用解释器执行e:/project中的Test.class字节码。

      注意: -cp 是指定用户类文件的位置,比如上面的Test.class的位置。这里因为要寻找Test.class类文件,而不是Test.java源代码文件,所以要通过-cp指定。千万没有这样的执行命令: java e:/project/Test


      (2) Test.java源代码

Java代码
  1. <span style="font-size: small;">//缺省包,但源代码中引用了一个JAR包内的自定义类,这个JAR包位于c:/目录下  
  2.   
  3. import net.single.util.SL;  //导入自定义JAR包中的类  
  4. public class Test{  
  5.        private SL aObject=new SL(); //初始化JAR中的SL类  
  6.        public static void main(String[] args){  
  7.        ......  
  8.        }  
  9. }</span>  
//缺省包,但源代码中引用了一个JAR包内的自定义类,这个JAR包位于c:/目录下import net.single.util.SL;  //导入自定义JAR包中的类public class Test{       private SL aObject=new SL(); //初始化JAR中的SL类       public static void main(String[] args){       ......       }}

       编译命令:javac -cp c:/single.jar e:/project/Test.java在e:/project目录下生成了Test.class

        注意:如果当前你要编译的java文件中引用了其它的类,但该引用类的.class文件不在当前目录下(或在其他目录下,或在.zip/.jar内),这种情况下就需要在javac命令后面,加上-cp/-classpath参数来指明这些类的位置。一般来说有三种指定方式:

              ① 绝对或相对路径:javac -cpc:/single.jar Test.java 或javac -cp ../single.jarTest.java  (其中 .. 表示上一级目录
             
系统变量:javac -cp%CLASSPATH% Test.java (其中:%CLASSPATH%表示使用系统变量CLASSPATH的值进行查找,这里假设single.jar的路径就包含在CLASSPATH系统变量中)

              ③ 当前目录: javac -cp./single.jar Test.java (其中 . 表示当前目录


       解释执行命令:【java -cp c:/single.jar;e:/project Test

       注意:① -cp的路径不仅指定了所需要的single.jar的位置,还必须指出编译后的Test.class的位置。

              ② 类路径中的不同项目要用分隔符区分,Unix系统的分隔符是冒号(:),Windows的是分号(;)

            

      (3) Test.java 源代码

Java代码
  1. <span style="font-size: small;">//该类在net.single包中,类中没有引入其他目录下的自定义类  
  2. package net.single;  
  3.   
  4. public class Test{  
  5.       .....  
  6.       public static void main(String[] args){  
  7.        .....  
  8.       }  
  9. } </span>  
//该类在net.single包中,类中没有引入其他目录下的自定义类package net.single;public class Test{      .....      public static void main(String[] args){       .....      }} 

         编译命令:【javac-d . e:/project/Test.java

        注意:① 如果没有-d而直接编译javace:/project/Test.java。将会在e:/project目录下直接生成一个Test.class,但此Test.class无法解释执行,因为它实际上在edu.single包中。所以必须将包一起编译出来,这里用了-d参数。

                ② 上面的编译结果将在e:/目录下自动根据包的结构形式创建文件目录,e:/net/single/Test.class

        解释执行命令: 【java-cp e:/ net.single.Test

           

     现在我们总结一下:

     [a.] 没有IDE环境,编译一个大型项目是很困难的,因为必须把需要被其他类引用的类先编译,而且最好把包结构一起编译出来。所以一般命令格式如下:

     编译: javac -cp (需要引入的类文件路径1;需要引入的类文件路径2;....)-d (编译出的类文件存放的位置目录) (待编译文件路径)

     执行: java -cp (需要解释执行的类文件路径) (带包的类文件)


      例:现在要编译一个类源码: Test.java,其中该类位于E:/project/下

            (1.  Test源代码中使用了一个JAR包中的类,这个single.jar包位于C:/目录下。

            (2.  Test源代码中使用了一个自定义类Content,这个类的源代码Content.java位于E:/下

            (3.  Test所在包为net.single,Content所在包为net.single.cont


      解决: 步1:由于Test使用了Content类,所以必须先编译Content,而且Content类在E:/目录下,而且 属于包net.single.cont

                        编译命令:  javac -d . e:/Content.java

                        编译结果:  在Content.java的当前目录下生成了一个  net/single/cont/Content.class   文件(带包结构),即e:/net/single/cont/Content.class

               步2:编译Test类,并指明所引入的single.jar包和Content.class的位置

                        编译命令:  javac -cp c:/single.jar;e:/net/single/cont -d . e:/project/Test.java

                        编译结果: 在Test的上一级目录下生成了一个 net/single/Test.class 文件,即e:/ net/single/Test.class

               步3:解释执行Test.class

                        执行命令:  java -cp c:/single.jar;e:/ net.single.Test

 

3、编译器,虚拟机如何定位到类的

Java代码
  1. package net.single;  
  2.   
  3. import java.util.*;  
  4. import net.single.util.*;  
  5.   
  6. public class Test{  
  7.      //SingleUtil类在c:/single.jar中的net.single.util包下  
  8.      private SingleUtil sut=new SingleUtil();   
  9. }  
package net.single;import java.util.*;import net.single.util.*;public class Test{     //SingleUtil类在c:/single.jar中的net.single.util包下     private SingleUtil sut=new SingleUtil(); }

            编译命令:  javac -cp c:/single.jar -d . e:/project/Test.java

 

         编译器首先找到e:/project/Test.java。然后对Test源代码进行编译,当编译到创建SingleUtil类对象的语句时,编译器要开始寻找SingleUtil.class的位置。编译器首先查找包含这个类的所有包的位置,并查询所有的import指令,确定其中是否包含了被引用了的类。

       如上面的Test.java,编译器将试图查找java.lang.SingleUtil,java.util.SingleUtil,net.single.util.SingleUtil以及当前包中的SingleUtil(即net.single.SingleUtil)。编译器将在三个部分中查找类文件:

       (1) 在JDK的lib目录下的标准类库文件中查找java.lang,java.util和net.single.util包。显然只能找到java.lang和java.util包。然后在这两个包中查找SingleUtil类文件。当然是找不到的。

       (2) 在编译命令中-cp参数表明的类路径(C:/single.jar)下查找java.lang,java.util和net.single.util包。显然只能找到net.single.util包,然后在里面找到SingleUtil类文件。

      (3) 在Test.java的当前目录下查找SingleUtil,也是没有的。

       如果没有找到SingleUtil,或者找到多个SingleUtil。编译器报错。