在C盘的根目录中新建一个子目录,名为“JavaTest”,以作为存放Java源代码的地方。打开XP中的记事本,先将其保存到JavaTest文件夹中,在“文件名”文本框中输入"Hello.java"。注意,在文件名的前后各加上一个双引号,否则,记事本就会将其存为"Hello.java.txt"的文本文件。然后输入以下代码:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, world");
}
}
再次保存文件。
在命令行窗口中输入
cd C:\JavaTest
将当前路径转入JavaTest中。然后,输入
javac Hello.java
由于我们是在源代码的当前路径下编译,因此,不会出现classpath设置有误的问题。
在命令行窗口中输入java Hello,屏幕出现了
Hello world
因此一切正常。下面我们开始人为地将问题复杂化,在非当前工作路径中编译及运行,看看结果如何。
在命令行窗口中输入
cd C:
转入到C盘根目录上,当前路径离开了存放源码的工作区。输入
javac Hello.java
屏幕出现:
error: cannot read: Hello.java
1 error
找不到Hello.java了。我们要给它指定一个路径,告诉它到C:\JavaTest去找Hello.java文件。输入
javac C:\JavaTest\Hello.java
OK,这回不报错了,编译成功。
输入
java C:\JavaTest\Hello
这回屏幕出现:
Exception in thread "main" java.lang.NoClassDefFoundError: C:\JavaTest\Hello
意思为在“C:\JavaTest\Hello”找不到类的定义。明明C:\JavaTest\Hello是一个.class文件,为什么就找不到呢?原来,Java对待.java文件与.class文件是有区别的。对.java文件可以直接指定路径给它,而java命令所需的.class文件不能出现扩展名,也不能指定额外的路径给它。
那么,如何指定路径呢?对于Java所需的.class文件,必须通过classpath来指定。
依照第5步,弹出“环境变量”窗口,在用户变量中新建一个变量,变量名为“classpath”,变量值为"C:\JavaTest"。一路按“确定”退出。关闭原命令行窗口,打开新的命令行窗口,输入
java Hello
“Hello world”出来了。由此可见,在“环境变量”窗口中设置classpath的目的就是告诉JDK,到哪里去寻找.class文件。这种方法一旦设置好,以后每次运行java或javac时,在需要调用.class文件时,JDK都会自动地来到这里寻找。因此,这是一个全局性的设置。
除了这种在环境变量”窗口中设置classpath的方法之外,还有另一种方法,即在java命令后面加上一个选项classpath,紧跟着不带扩展名的class文件名。例如,
java -classpath C:\JavaTest Hello
JDK遇到这种情况时,先根据命令行中的classpath选项中指定的路径去寻找.class文件,找不到时再到全局的classpath环境变量中去寻找。这种情况下,即使是没有设置全局的classpath环境变量,由于已经在命令行中正确地指定类路径,也可以运行。
为了在下面的例子中更好地演示classpath的问题,我们先将全局的classpath环境变量删除,而在必要时代之以命令行选项-classpath。弹出“环境变量”窗口,选中“classpath”的变量名,按“删除”键。
此外,java命令中还可以用cp,即classpath的缩写来代替classpath,如java -cp C:\JavaTest Hello。特别注意的是,JDK 1.5.0之前,javac命令不能用cp来代替classpath,而只能用classpath。而在JDK 1.5.0中,java及javac都可以使用cp及classpath。因此,为保持一致,建议一概使用classpath作为选项名称。
我们再次人为地复杂化问题。关闭正在编辑Hello.java的记事本,然后将JavaTest文件夹名称改为带空格的“Java Test”。在命令行中输入
javac C:\Java Test\Hello.java
长长的洋文又出来了,但这回却是报错了:
javac: invalid flag: C:\Java
JDK将带有空格的C:\Java Test分隔为两部分"C:\Java"及"Test\Hello.java",并将C:\Java视作为一个无效的选项了。这种情况下,我们需要将整个路径都加上双引号,即
javac "C:\Java Test\Hello.java"
这回JDK知道,引号里面的是一个完整的路径,因此就不会报错了。同样,对java命令也需要如此,即
java -classpath "C:\Java Test" Hello
对于长文件名及中文的文件夹,XP下面可以不加双引号。但一般来说,加双引号不容易出错,也容易理解,因此,建议在classpath选项中使用双引号。 我们再来看.java文件使用了其他类的情况。在C:\Java Test中新建一个Person.java文件,内容如下:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
然后,修改Hello.java,内容如下:
public class Hello {
public static void main(String[] args) {
Person person = new Person("Mike");
System.out.println(person.getName());
}
}
在命令行输入
javac "C:\Java Test\Hello.java"
错误来了:
C:\Java Test\Hello.java:3: cannot find symbol
symbol: class Person
JDK提示找不到Person类。为什么
javac "C:\Java Test\Hello.java"在第14步中可行,而在这里却不行了呢?第14步中的Hello.java文件并没有用来其他类,因此,JDK不需要去寻找其他类,而到了这里,我们修改了Hello.java,让其使用了一个Person类。 根据第11步,我们需要告诉JDK,到哪里去找所用到的类,即使这个被使用的类就与Hello.java一起,同在C:\Java Test下面!输入
javac -classpath "C:\Java Test" "C:\Java Test\Hello.java"
编译通过,JDK在C:\Java Test文件夹下同时生成了Hello.class及Person.class两个文件。实际上,由于Hello.java使用了Person.java类,JDK先编译生成了Person.class,然后再编译生成Hello.class。因此,不管Hello.java这个主类使用了多少个其他类,只要编译这个类,JDK就会自动编译其他类,很方便。输入
java -classpath "C:\Java Test" Hello
屏幕出现了
Mike
成功。
说明了在Hello.java中如何使用一个我们自己创建的Person.java,而且这个类与Hello.java是同在一个文件夹下。在这一步中,我们将考查Person.java如果放在不同文件夹下面的情况。
先将C:\Java Test文件夹下的Person.class文件删除,然后在C:\Java Test文件夹下新建一个名为DF的文件夹,并将C:\Java Test文件夹下的Person.java移动到其下面。在命令行输入
javac -classpath "C:\Java Test\DF" "C:\Java Test\Hello.java" (注意这里不用;区分,用空格就可以!)
编译通过。这时javac命令没有什么不同,只需将classpath改成C:\Java Test\DF就行了。
在命令行输入
java -classpath "C:\Java Test" Hello
这时由于Java需要找在不同文件夹下的两个.class文件,而命令行中只告诉JDK一个路径,即C:\Java Test,在此文件夹下,只能找到Hello.class,找不到Person.class文件,因此,错误是可以预料得到的:
Exception in thread "main" java.lang.NoClassDefFoundError: Person
at Hello.main(Hello.java:3)
果真找不到Person.class。
在设置两个以上的classpath时,先将每个路径以双引号引起来,再将这些路径以“;”号隔开,并且每个路径与“;”之间不能带有空格。因此,我们在命令行重新输入:
java -classpath "C:\Java Test";"C:\Java Test\DF" Hello
编译成功。但也暴露出一个问题,如果我们需要用到许多分处于不同文件夹下的类,那这个classpath的设置岂不是很长!有没有办法,对于一个文件夹下的所有.class文件,只指定这个文件夹的classpath,然后让JDK自动搜索此文件夹下面所有相应的路径?有,只要使用package。
package简介。Java中引入package的概念,主要是为了
解决命名冲突的问题。比如说,在我们的例子中,我们设计了一个很简单的Person类,如果某人开发了一个类库,其中恰巧也有一个Person类,当我们使用这个类库时,两个Person类出现了命名冲突,JDK不知道我们到底要使用哪个Person类。更有甚者,当我们也开发了一个很庞大的类库,无可避免地,我们的类库中与其他人开发的类库中命名冲突的情况就会越来越多。总不能为了避免自己的类名与其他人开发的类名相同,而让每个编程人员都绞尽脑汁地将一个本应叫Writer的类强行改名为SarkuyaWriter,MikeWriter, SmithWriter吧?
自定义package的名称可以由各个程序员自由创建。作为避免命名冲突的手段,package的名称最好足以与其他程序员的区别开来。在互联网上,每个域名都是唯一的,因此,Sun推荐将你自己的域名倒写后作为package的名称。如果你没有自己的域名,很可能只是因为囊中羞涩而不去申请罢了,并不见得你假想的域名与其他域名发生冲突。例如,笔者假想的域名是sarkuya.com,目前就是唯一的,因此我的package就可以定名为com.sarkuya。谢谢Java给了我们一个免费使用我们自己域名的机会,唯一的前提是倒着写。当然,每个package下面还可以带有不同的子package,如com.sarkuya.util,com.sarkuya.swing,等等。
定义package的方式是在相应的.java文件的第一行加上“package packagename;”的字样,而且每个.java文件只能有一个package。实际上,Java中的package的实现是与计算机文件系统相结合的,即你有什么样的package,在
硬盘上就有什么样的存放路径。例如,某个类的package名为com.sarkuya.util,那么,这个类就应该必须存放在com/sarkuya/util的路径下面。至于这个com/sarkuya/util又是哪个文件夹的子路径,
package除了有避免命名冲突的问题外,还引申出一个保护当前package下所有类文件的功能,主要通过为类定义几种可视度不同的修饰符来实现:public, protected, private, 另外加上一个并不真实存在的friendly类型。
对于冠以public的类、类属变量及方法,包内及包外的任何类均可以访问;protected的类、类属变量及方法,包内的任何类,及包外的那些继承了此类的子类才能访问;private的类、类属变量及方法,包内包外的任何类均不能访问;如果一个类、类属变量及方法不以这三种修饰符来修饰,它就是friendly类型的,那么包内的任何类都可以访问它,而包外的任何类都不能访问它(包括包外继承了此类的子类),因此,这种类、类属变量及方法对包内的其他类是友好的,开放的,而对包外的其他类是关闭的。
前面说过,package主要是为了解决命名冲突的问题,因此,处在不同的包里面的类根本不用担心与其他包的类名发生冲突,因为JDK在默认情况下只使用本包下面的类,对于其他包,JDK一概视而不见:“眼不见心不烦”。如果要引用其他包的类,就必须通过import来引入其他包中相应的类。只有在这时,JDK才会进行进一步的审查,即根据其他包中的这些类、类属变量及方法的可视度来审查是否符合使用要求。如果此审查通不过,编译就此卡住,直至你放弃使用这些类、类属变量及方法,或者将被引入的类、类属变量及方法的修饰符改为符合要求为止。如果此审查通过,JDK最后进行命名是否冲突的审查。如果发现命名冲突,你可以通过在代码中引用全名的方式来显式地引用相应的类,如使用
java.util.Date = new java.util.Date()
package的第三大作用是简化classpath的设置。还记上面的命令,这里重新引用其java命令:
java -classpath "C:\Java Test";"C:\Java Test\DF" Hello
我们必须将所有的.class文件的路径一一告诉JDK,而不管DF其实就是C:\Java Test的子目录。如果要用到100个不同路径的.class文件,我们就得将classpath设置为一个特别长的字符串,很累。package的引入,很好地解决了这个问题。package的与classpath相结合,通过import指令为中介,将原来必须由classpath完成的类路径搜索功能,很巧妙地转移到import的身上,从而使classpath的设置简洁明了。我们先看下面的例子。
先在Hello.java中导入DF.Person。代码修改如下:
import DF.Person;
public class Hello {
public static void main(String[] args) {
Person person = new Person("Mike");
System.out.println(person.getName());
}
}
再将DF子文件夹中的Person.java设置一个DF包。代码修改如下:
package DF;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
好了,神奇的命令行出现了:
javac -classpath "C:\Java Test" "C:\Java Test\Hello.java"
java -classpath "C:\Java Test" Hello
(在我的jdk1.6上,没有设置classpath,上面的两条命令可以简化为:
javac Hello.java
java Hello
呵呵,不知道是什么原因啊!
)
posted on 2008-10-09 16:19
fly 阅读(253)
评论(0) 编辑 收藏 所属分类:
java学习