`
talentluke
  • 浏览: 593018 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

javac和java的路径问题

 
阅读更多
javac和java的路径问题
设定项目目录为packageTest,举三个例子来讨论javac和java两个命令对路径的要求。
例1:
javac的搜索根目录为当前目录,例如,在test下建立如下目录:aaa/bbb/ccc,再在test下建立一个文件:Main.java,内容如下:
view plaincopy to clipboardprint?
1.	package aaa.bbb.ccc;  
2.	import java.io.*;  
3.	  
4.	public class Main {  
5.	    public static void main (String[] args) throws IOException {  
6.	        System.out.println("I am class Main.");  
7.	        b.say();  
8.	    }  
9.	    static B b = new B ();  
10.	}  
11.	  
12.	class B {  
13.	    public void say ()  
14.	    {  
15.	        System.out.println("I am class B.");  
16.	    }  
17.	}  
在packageTest目录下编译:
$ javac Main.java
仍在packageTest目录下运行:
$ java Main
失败。因为Main类在包aaa.bbb.ccc中,java会在CLASSPATH(假设已经将当前目录:./加入到了CLASSPATH中)下找aaa/bbb/ccc/Main.class,当然找不到。实际上,即使把CLASSPATH设为./aaa/bbb/ccc,java仍然找不到Main,这里涉及到一个fully-qualified class name的概念,即,当给一个类打了包,类的名字就不再是原来的名字,必须加上包的名字,在本例子中,Main类被打在aaa/bbb/ccc包中后,其fully-qualified class name为aaa.bbb.ccc.Main。当然,这和将类打在默认包中时的情况不同,类打在默认包中时没有fully-qualified class name,也可以说其fully-qualified class name就是原生的类名。好了,再运行:
$ java aaa.bbb.ccc.Main
仍失败!错误提示说没有找到 main class,哦,对,原来是没把Main拷到aaa/bbb/ccc中去,拷进去后再运行:
$ java aaa.bbb.ccc.Main
仍失败!!错误提示说没有找到 main class,不知道为什么还会提示这个错误,其实错误原因是B.class放的位置不对由于class B和Main放在同一个翻译单元中,故编译器图方便直接把B.class放在了当前目录中,实际上class B也是aaa.bbb.ccc包中的成员,所以运行时java没有在这个包中找到class B,当把B.class拷到aaa/bbb/ccc目录下后再运行:
$ java aaa.bbb.ccc.Main
成功显示结果:
I am class Main.
I am class B.
例2:
对Main.java做修改,把要使用的类B移出当前翻译单元:
view plaincopy to clipboardprint?
1.	package aaa.bbb.ccc;  
2.	import java.io.*;  
3.	  
4.	public class Main {  
5.	    public static void main (String[] args) throws IOException {  
6.	        System.out.println("I am class Main.");  
7.	        b.say();  
8.	    }  
9.	    static B b = new B ();  
10.	}  
然后在packageTest下新建一个B.java:
view plaincopy to clipboardprint?
1.	package aaa.bbb.ccc;  
2.	import java.io.*;  
3.	public class B {  
4.	    void say () {  
5.	        System.out.println("I am the goddamn B!");  
6.	    }  
7.	}  
编译:
$ javac Main.java
失败。原因是javac没有找到symbol: class B,把B.java拷到aaa/bbb/ccc下后,编译成功,并在aaa/bbb/ccc下生成了B.class。原来javac在本翻译单元中找不到B后会去包aaa.bbb.ccc中找,所以package语句不止跟java有关,javac也要用它。实际上,javac需要的也是class文件,即javac发现import语句后,也要去CLASSPATH中去找编译时所需要的类,如果class文件存在,直接使用;如果不存在,对应的java源文件存在也行,这时,javac会先将B.java编译成B.class,这样Main中所需要的aaa.bbb.ccc.B就存在了,编译通过。因此,不论是java还是javac还是其它程序,只要其找的是class文件,就需要到CLASSPATH指定的目录中去找。如果CLASSPATH不设,默认为当前目录".",故即使echo出的$CLASSPATH什么也没有,它也是".",这一点比较奇怪。另外,目前还不清楚java的“库“放在哪,比如上面程序中的java.io.*,而且java怎么去找这些class,至少应该不是通过CLASSPATH。javac编译过程中寻找类名的顺序是定死的,这个顺序参见附记。
接下来在test中运行:
$ java aaa.bbb.ccc.Main
失败。忘记把Main.class拷到aaa/bbb/ccc中去了。拷过去以后在test中执行上面命令,结果为:
I am class Main.
I am the goddamn B!
例3:
主要想明确一下javac搜索类型的顺序。
Main.java如例1:
view plaincopy to clipboardprint?
1.	package aaa.bbb.ccc;  
2.	import java.io.*;  
3.	  
4.	public class Main {  
5.	    public static void main (String[] args) throws IOException {  
6.	        System.out.println("I am class Main.");  
7.	        b.say();  
8.	    }  
9.	    static B b = new B ();  
10.	}  
11.	  
12.	class B {  
13.	    public void say ()  
14.	    {  
15.	        System.out.println("I am class B.");  
16.	    }  
17.	}  
另外还有B.java:
view plaincopy to clipboardprint?
1.	package aaa.bbb.ccc;  
2.	import java.io.*;  
3.	public class B {  
4.	    void say () {  
5.	        System.out.println("I am the goddamn B!");  
6.	    }  
7.	}  
这次两个class都放在aaa/bbb/ccc下,在packageTest中执行命令:
$ javac aaa/bbb/ccc/Main.java
在aaa/bbb/ccc下生成Main.class和B.class,然后运行:
$ java aaa.bbb.ccc.Main
结果为:
I am class Main.
I am class B.
可见生成的B.class由Main.java中的class B生成,这体现了javac的一种搜索类型的顺序。
 
javac参数(-classpath, -sourcepath)详解
首先是官方说法:
-classpath:
设置用户类路径,它将覆盖 CLASSPATH 环境变量中的用户类路径。若既未指定 CLASSPATH 又未指定 -classpath,则用户类路径由当前目录构成。
 
-sourcepath:
sourcepath用来查找源文件的,具体来说就是,在我们编译A时,如果A依赖B,而B在classpath中又找不到,这时就要在sourcepath中查找B的源文件。指定用以查找类或接口定义的源代码路径。与用户类路径一样,源路径项用分号 (;) 进行分隔,它们可以是目录、JAR 归档文件或 ZIP 归档文件。如果使用包,那么目录或归档文件中的本地路径名必须反映包名。
注意:通过类路径查找的类,如果找到了其源文件,则可能会自动被重新编译。
 
    官方说法很简洁,但是具体操作起来总觉得不太清晰,我们还是找几个例子,来具体分析一下:
具体例子:
    假设我们有如下的目录结构:
    src-|
          |-foo-|
                   |-Testfoo.java
          |-baz-|
                    |-Testbaz.java
    classes-|
其中Testfoo.java:
package foo;
public class Testfoo {
//....
}
其中Testbaz.java:
package baz;
import foo.Testfoo;
public class Testbaz {
//...
}
也就是说Testbaz对Testfoo有引用。
我们目标是把Testbaz编译到目录classes里面,试用如下的命令:
javac -d classes src/baz/Testbaz.java
命令失败,因为找不到它依赖的Testfoo。我们可以用以下三种方式来实现:
1.我们最容易考虑到的就是编译被依赖的Testfoo类,并将其加入Testbaz的CLASSPATH
javac -d classes src/foo/Testfoo.java
javac -d classes -classpath classes src/baz/Testbaz.java
第二行使用了-classpath,使得编译器在寻找Testfoo类的时候以classes为根目录,根据根目录和package名,类名最终定位了需要用的(已编译出来的)Testfoo类。
 
2.在编译Testbaz的时候把被依赖的Testfoo类加入SOURCEPATH
javac -d classes -sourcepath src src/baz/Testbaz.java
在编译条件里面加入-verbose可以很清楚的看到,编译器在寻找Testfoo类的时候,以src为根目录,根据根目录和package名,类名最终定位了需要用的(源代码)Testfoo类。
 
3.把CLASSPATH和SOURCEPATH两者都加进来
javac -d classes src/foo/Testfoo.java
javac -d classes -sourcepath src -classpath classes src/baz/Testbaz.java
两个属性都被加入,编译器首先会判断Testfoo.class和Testfoo.java是否同时存在。如果单独存在,则适应于以上的方法之一。如果同时存在,则判断.class是否是.java的最新编译,如果有差异,则重新编译.java来覆盖.class
 
有必要补充一下-d参数:
-d参数是很好的把源程序和目标代码分离的参数。-d制定的是目标代码的根目录,源文件的包的结构将以目录形式反映到根目录上。美中不足的是-d需要指定已经存在的目录,不能自动创建。
再来一例子
文件结构如下,其中A.java头部引用B和C
 
files.txt为sourcepath列表,注意路径以分号分隔且在同一行(不知为什么,可能与classpath规范类似,路径以分号分隔吧),不能以回车或者空格分隔,另外路径指类全名(含包名)所在的目录,如A .java中import c.C;指c.C所在的目录即E:\test\src,而不是C.java的路径即E:\test\src\c。
 
javas.txt包含多个要编译的java源文件,以空格或者回车分隔,分号不行。也可以将多个文件写在javac命令行中,文件名以空格分隔。要编译的源文件要写成含”\”符号的完整路径,不能写成含”.”符号的包形式,这与java命令不同,如javac E:\test\b\B.java与java b.B。
 
E:\test\a\A.java
E:\test\b\B.java
E:\test\src\c\C.java
 
 
 
 
 
 

 

分享到:
评论

相关推荐

    spring-boot-querydsl-bug:说明 querydsl 集合和 spring boot 的 javac 调用类路径问题

    spring-boot-querydsl-bug 说明 querydsl 集合和 spring boot 的 javac 调用类路径问题如果作为 spring boot 应用程序运行,它将调用 javac 来编译 QueryDSL 生成的代码,但它找不到任何类。 都有最新的稳定版和最新...

    获取类路径下资源

    所谓java中的类路径是告诉java解释器和javac编译器去哪里找它们要执行或导入的类。类(包括class文件)可以存储在目录或jar文件中,或者存储在两者的组合中,但是只有在它们位于类路径中的某个地方时,java编译器或...

    java环境变量jdk1.8设置

    java环境变量设置,环境变量是操作系统提供的一种机制,用于存储和获取关键信息以方便应用程序和用户。在Java开发中,我们经常需要配置一些环境变量来指定Java运行时的一些参数。 JAVA_HOME:Java安装目录,用于指定Java...

    JAVA环境变量设置的作用.txt

    因为通过要通过命令行的命令启动JAVA,JAVAC等编译工具和解释工具,系统必须要知道他们所在的位置,PATH就是用来指明他们的位置的. 3.CLASSPATH该变量是JAVA加载类(class or lib)的路径.只有在classpath设置的路径中的...

    java获取当前windows进程pid

    功能:获取java进程pid ...4. cl PidTool.c -FePidTool.dll -LD -I"D:\Development\Java\jdk1.6.0\include" -I"D:\Development\Java\jdk1.6.0\include\win32" ,生成dll文件,路径最好加"",以免出问题!

    使用Java编写脚本来将PDF转换为图像,Java的PDF处理库,Apache PDFBox

    2、执行以下命令来运行生成的类文件,并提供PDF文件的路径和输出文件夹的路径作为命令行参数: java PDFToImageConverter path_to_pdf_file.pdf path_to_output_folder 请将path_to_pdf_file.pdf替换为您要转换的PDF...

    JAVA--JDK环境变量的配置

     C:\Program Files\Java\j2sdk1.5.0 (JDK的安装路径)  b.新建 PATH  %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin  c.新建 CLASSPATH  .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar  3.测试环境变量配置...

    JAVA程序命令行下的执行

    (如果是javac的话需要 javac xx\xxx\aaa.java,必须用路径的形式) 注意如果源文件的结构是Package的话,classpath指定到.class文件上面,然后 直接执行aaa是不行的(javac的话可以),必须按上面的规则。举个例子

    java源码路径-lein-javac-resources:从:java-source-paths复制资源以编译路径

    java原始路径lein-javac-resources Leiningen插件可用于:java-source-paths资源文件。 该插件旨在用于具有遗留Java代码库的项目,其中资源文件与Java源文件一起放置。 用法 将插件包括在project.clj的:plugins矢量中...

    java jdk8 学习笔记

    第一章 1.Java 编程语言刚开始 Oak 橡树 办公室外 已被注册 边喝咖啡边讨论名称 2.动态加载类别文档、字符串池(String Pool)等特性为节省内存而设计 ...所以javac和java都需要指定好所依赖的路径。

    JAVA编译器,适合新手,更时候老手

    本程序使用的都是黑窗口模式,换了背景色,调用的都是原编译器在DOS模式下的javac和java程序。虽然比不上Eclipse的集成度,但个人测试了几十个JAVA程序,感觉很上手,所以奉献给大家,资源分不多,感谢大家支持!【另...

    Java程序设计基础:环境变量配置.pptx

    对于Java程序开发而言,主要会使用JDK的两个命令:javac.exe、java.exe Java环境变量 命令所在路径:C:\Program Files\Java\jdk1.8.0_20\bin 但是这些命令由于不属于windows自己的命令,需要进行路径配置 Java环境...

    配置java环境变量.txt

    1、下载jdk(http://java.sun.com/javase/downloads/index.jsp),我下载的版本是:jdk-6u14-windows-i586.exe 2、安装jdk-6u14-windows-i586.exe ...path:系统在任何路径下都可以识别java,javac命令。

    27天成为Java大神

    1:计算机概述 ... (1)在环境变量的path后添加javac和java所在的目录,添加在最前面,有多个会按顺序查找 (2)创建环境变量JAVA_HOME为exe目录所在,path:%JAVA_HOME%\bin;原来的路径 classpath

    linux资源多路径配置

    linux资源多路径配置 非常好的技术文档

    Java快速命令编译助手(JCR)

    有了它我们就不必要:开始 输入 cmd 然后再转到当前盘,当前路径,再输入Javac 文件名.Java 也不用输入:Javac 文件名 了,现在我们只要把我们要编译的源文件拖放到本程序的图标或快捷方式的图标上即可自动进行编译...

    plexus-compiler-javac-1.8.1.jar.zip

    java jar包,亲测试可用 ...把一个JAR文件添加到系统的classpath环境变量之后,java通常会把这个JAR文件当做一个路径来处理。通常使用jar命令来压缩,可以把一个或多个路径全部压缩成一个JAR文件。

    JAVA实验报告一.docx

    Java 的编译命令 (javac),执行命令 (java) 和一些工具命令 (javadoc, jdb 等) 都在其安装路径下的 bin 目录中。 CLASSPATH:该环境变量也指定一个路径列表,是用于搜索 Java 编译或者运行时需要用到的类。在 ...

    java环境搭建.docx

    classpath是我们类存放的根路径,我们可以设置classpath来在任意路径来执行java的class类 .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;(. 代表当前路径) java运行机制、java标识符 java...

    java02——Java概述

    其中比较重要的有javac(JDK提供的编译工具)和java(JDK提供的) 注:Java在windows操作系统中不能直接运行->需要对Java进行编译 2)如何理解编译? 答:编译的动作其实就是翻译,把操作系统看不懂的内容变成操作...

Global site tag (gtag.js) - Google Analytics