`

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

阅读更多

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


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

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


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

    (1) Test.java源代码

//缺省包,该程序源代所在位置: e:/project/ Test.java

public class Test{
      .....
      public static void main(String[] args){
      .....
      }
} 



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

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

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


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

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


      (2) Test.java源代码

//缺省包,但源代码中引用了一个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 -cp c:/single.jar Test .java 或 javac -cp ../single.jar Test .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 源代码

//该类在net.single包中,类中没有引入其他目录下的自定义类
package net.single;

public class Test{
      .....
      public static void main(String[] args){
       .....
      }
} 



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

        注意: ① 如果没有-d而直接编译javac e:/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、编译器,虚拟机如何定位到类的

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。编译器报错。

 

 

     

 

11
0
分享到:
评论
1 楼 lfsfxy9 2011-08-24  
博主,你知道eclipse中如何对引入的jar包进行管理吗 ?

我想知道,项目中引入的jar包,被改名之后, import 引入关系依然成立.

这就是说,IDE认识的不是包名,而是具体的com.*.* .

你知道这里边的机制吗?

我想了解一下,谢谢.

相关推荐

    Java虚拟机

    讲解了虚拟机的热点探测方法、HotSpot的即时编译器、编译触发条件,以及如何从虚拟机外部观察和分析JIT编译的数据和结果;第五部分探讨了Java实现高效并发的原理,包括JVM内存模型的结构和操作;原子性、可见性和...

    Java虚拟机规范(Java SE 8版)

    也就是《Lambda Expressions for the Java Programming Language》(Java编程语言的lambda表达式)时,Oracle公司的Dan Smith向虚拟机实现者咨询了将default方法集成到常量池和方法结构、方法与接口方法解析算法,...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 170 第7章 虚拟机类加载机制 / 171 7.1 概述 / 171 7.2 类加载的时机 / 172 7.3 类加载的过程 / 176 7.3.1 加载 / 176 7.3.2 验证 / 178 7.3.3 准备 / 181 7.3.4 解析 / 182 7.3.5 初始化 / 186 7.4 类...

    java相关的2024面试题集锦

    - 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制 - 类加载机制采用懒加载的方式 - 遇到new、getstatic、...

    Java 虚拟机面试题全面解析(干货)

    Java 虚拟机面试题全面解析,《深入理解Java虚拟机》干货版,自己总结,希望能够帮助大家,免费下载~什么是类加载机制? 虚拟机和物理机的区别是什么? 运行时栈帧结构 Java方法调用 什么是方法调用? Java的方法调用,...

    Java 1.6 API 中文 New

    java.lang.management 提供管理接口,用于监视和管理 Java 虚拟机以及 Java 虚拟机在其上运行的操作系统。 java.lang.ref 提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。 java.lang.reflect 提供类和...

    java面试题-附答案

    JDK(Java Development Kit)是Java开发工具包,它提供了Java的开发环境(提供了编译器javac等工具,用于将java文件编译为class文件)和运行环境(提供了JVM和Runtime辅助包,用于解析class文件使其得到运行)。...

    JAVA小区物业管理系统

    利用JDK中的Java解析器,将字节码文件转化为你的系统能够理解的指令,加以执行。 2.2.4 JDBC简介 Java数据库连接JDBC(Java DateBase Connectivity)与ODBC(Open DataBase Connectivity)开放式数据库连接的概念和...

    java 面试题 总结

    java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。 6、说出Servlet的生命周期,并说出Servlet和CGI的区别。 Servlet被服务器实例化后,容器运行其init方法,...

    一次性精通JVM JAVA虚拟机

    第3章 类的加载、解释、编译,本章节带你深入理解类加载器的分类、范围、双亲委托策略,自己手写类加载器,理解字节码解释器、即时编译器、混合模式、热点代码检测、分层编译等核心知识。 第4章 内存模型,本章节...

    关于JVM的总结

    类被加载到虚拟机内存开始,到卸载出内存为止,生命周期包含: 加载,验证,准备,解析,初始化,使用,卸载 7个阶段,加载,验证,准备,初始化和卸载这5个顺序是确定的,解析阶段则不一定,他在某些情况下可以在...

    GraalVM最佳实践,使用Java开发.rar

    到目前为止,GraalVM提供了两种运行Java程序的方法:将Java HotSpot VM与GraalVM JIT(即时)编译器一起使用,以及第二种方法:使用GraalVM Native Image编译为本机可执行文件。 今天,我们很高兴地宣布一种在...

    java源码debug-Java-Subset-Compiler-Debugger:为Java的子集语言而构建的编译器,目的是在JVM上模拟源

    完全由Java构建的项目,通过对源代码的词法分析(将字符流转化成令牌),使用OOP在Java虚拟机上模拟源代码的编译,然后使用递归下降处理对其进行解析。 这些标记放在抽象语法树上,然后由类型检查约束,并引用符号表...

    详解JAVA类加载机制(推荐)

    JAVA源码编译由三个过程组成: 1、源码编译机制。 2、类加载机制 ...系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行

    java多线程笔试题-awesome-rubies:一组很棒的Ruby(编译器、解释器、虚拟机、解析器、文档生成器、版本管理器等)

    Ruby(编译器、解释器、虚拟机、解析器、文档生成器、版本管理器等) 欢迎投稿。 缺什么吗? 发送拉取请求。 谢谢。 笔记: :gem_stone: 代表 RubyGems 页面,代表 GitHub 页面。 什么是Ruby? 作者:Noah Gibbs,...

    [Java参考文档].JDK_API 1.6

    java.lang.management 提供管理接口,用于监视和管理 Java 虚拟机以及 Java 虚拟机在其上运行的操作系统。 java.lang.ref 提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。 java.lang.reflect 提供类和...

    jsjs:jsjs 是在 Java 虚拟机之上用 JavaScript 编写的 JavaScript 引擎

    jsjs 是在 Java 虚拟机之上用 JavaScript 编写的 JavaScript 编译器 + 引擎 如何构建它? 首先,您需要一个与 Java 8 兼容的 JDK,然后您必须编辑脚本 run_build.js 中定义 JDK 位置的行 var java_home = "PATH_...

    java虚拟机源码-jvm_based_compiler:该程序实现了递归下降解析器,将源代码转换为字节码,以便生成的字节码可以在Java虚拟

    java虚拟机源码基于JVM的编译器 该程序通过使用递归下降解析器将源代码转换为字节码。 该程序假定源代码是基于附加的属性语法定义的。 将源代码转换为字节码后,可以使用jvm运行该程序。

    m4j:JAVA 腮腺炎

    尝试为 Java 虚拟机 (JVM) 创建一个 MUMPS 运行时环境,类似于 Groovy、Scala、Ruby、Python 等其他编程语言如何利用 JVM 平台 可以解释和执行 M 代码的基于 ANTLR 的词法分析器/解析器 可以将M代码编译成JVM字节码...

    oberonc:用于JVM的Oberon-07编译器

    尽管为堆栈机生成代码很简单,但是复杂的类文件格式以及考虑到Java语言设计JVM的事实使这一任务更加恶化。 实际上,JVM缺少支持Oberon功能所需的许多原语,特别是: 值类型 通过参考评估策略 过程变量(指向函数的...

Global site tag (gtag.js) - Google Analytics