问HelloWorld问题的人实在是太多了,而且经常都以“问一个最简单的问题”开头。其实回想一下,自己也是从这个阶段过来的,说一句“你好”,真的是一个最简单的问题吗?
首先,我们要假设一下我们的平台是Windows+JDK(Linux环境下也差不多)。这个环境是相当普遍、基础和入门的。确定已经正确安装JDK了,下一步是小心翼翼地敲入某本教程上的HelloWorld源码,存盘,然后编译,javac ...问题来了:
* 错误1:
'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件。
(javac: Command not found)
产生的原因是没有设置好环境变量path。
Win98下在autoexce.bat中加入path=%path%;c:/jdk1.2/bin
Win2000下则控制面板->系统->高级->环境变量->系统变量...看到了?双击Path,在后面加上c:/jdk1.2/bin。
当然我们假设JDK安装在了c:/jdk1.2目录下
好,再试试!javac HelloWorld
* 错误2:
HelloWorld is an invalid option or argument.
拜托,给点专业精神,java的源程序是一定要存成.java文件的,而且编译时要写全.java呀。
OK,javac HelloWorld.java (这回总该成了吧?)
* 错误3:
HelloWorld.java:1: Public class helloworld must be defined in a file called
"HelloWorld.java".public class helloworld{
这个问题嘛,是因为你的类的名字与文件的名字不一致。(谁说的,明明看到人家都有这样写的)OK,准确地说,一个Java源程序中可以定义多个类,但是,具有public属性的类只能有一个,而且要与文件名相一致。还有,main方法一定要放在这个public的类之中,这样才能java(运行)这个类。另外一点是Java语言里面是严格区分大小写的,初学者要注意呀。像上例中 helloworld 与 HelloWorld 就认为是不一样,因而...
oh... 好,改好了,嘻嘻...
javac HelloWorld.java
...(咦,怎么什么也没有呀?)//faint 这就是编译通过了!看看是不是多了一个HelloWorld.class?
按书上教的 java HelloWorld(不是java HelloWorld.class哟,因为在j2ee规范中java指令中的“.”是指路径的意思,如果是java HelloWorld.class 那么系统就会查找HelloWorld目录下的class.class文件,这样当然是不可能存在的)。
* 错误4:
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld
呵呵,这个嘛,就是著名的类路径(classpath)问题啦。实际上,类路径是在编译过程就涉及的Java中的概念。classpath就是指明去哪里找用到的类,就这么简单。由于我们的HelloWorld没用到其它的(非java.lang包中的)类,所以编译时没遇到这个问题。运行时呢,就要指明你的类在哪里了。解决方法嘛,可以用下面的命令运行:
java -classpath . HelloWorld
“.”就代表当前目录。当然这样做有点麻烦(是“太麻烦”!),我们可以在环境变量中设置默认的classpath。方法就照上述设置path那样。将classpath设为:classpath=.;c:/jdk1.2/lib/dt.jar;c:/jdk1.2/lib/tools.jar 后面的两个建议也设上,以后开发用的着。
java -classpath . HelloWorld(再不出来我就不学java了)
* 错误5:
Exception in thread "main" java.lang.NoSuchMethodError: main
(//咣当)别,坚持住。看看你的代码,问题出在main方法的定义上,写对地方了吗,是这样写的吗:
public static void main(String args[]) { // 一个字都不要差,先别问为什么了...对,包括大小写!
java -classpath . HelloWorld (听天由命了!)
Hello World!
(faint!终于...)
欢迎来到Java世界!所以说,无法运行HelloWorld 真的并不是一个“最简单的问题”。
附:HelloWorld.java
// HelloWorld.java
public class HelloWorld {
public static void main(String args[]) {
System.out.println("Hello World!");
}
}
http://www.xichy.cn/java/j2ee/469352.shtml
由于这两个问题新手问得较多, 且回答比较零散, 很难统一整理, 所 以就直接写了一篇, 还请大家见谅. 正文: 一, 类路径 (class path) 当你满怀着希望安装好了 java, 然后兴冲冲地写了个 hello world,然后编译, 运行, 就等着那两个美好的单词出现在眼前, 可是不幸的是, 只看到了 Can't find class HelloWorld 或者 Exception in thread "main" java.lang.NoSuchMethodError : maain. 为什么呢? 编译好的 class 明明在呀. 我们一起来看一看 java 程序的运行过程. 我们已经知道 java 是通过 java 虚拟机来解释运行的, 也就是通过 java 命令, javac 编译生成的 .class 文件就是虚拟机要执行的代码, 称之为字节码(bytecode), 虚拟机通过 classloader 来装载这些字节码, 也就是通常意义上的类. 这里就有一个问题, classloader 从 哪里知道 java 本身的类库及用户自己的类在什么地方呢? 或者有着缺省值(当前路径) . 或者要有一个用户指定的变量来表明, 这个变量就是类路径(classpath), 或者在运行 的时候传参数给虚拟机. 这也就是指明 classpath 的三个方法. 编译的过程和运行 的过程大同小异, 只是一个是找出来编译, 另一个是找出来装载. 实际上 java 虚拟机是由 java luncher 初始化的, 也就是 java (或 java.exe) 这个程序来做的. 虚拟机按以下顺序搜索并装载所有需要的类: 1, 引导类: 组成 java 平台的类, 包含 rt.jar 和 i18n.jar 中的类. 2, 扩展类: 使用 java 扩展机制的类, 都是位于扩展目录($JAVA_HOME/jre/lib/e xt) 中的 .jar 档案包. 3, 用户类: 开发者定义的类或者没有使用 java 扩展机制的第三方产品. 你必须在 命令行中使用 -classpath 选项或者使用 CLASSPATH 环境变量来确定这些类的位置. 我 们在上面所说的用户自己的类就是特指这些类. 列表, 至于类具体怎么找, 因为牵扯到 package 的问题, 下面将会说到, 暂时可认为 统基本上都是 ":", windows 多是 ";". 其可能的来源是: [/]$ java -cp /HelloWorld HelloWorld 东西都往里搁, 一些标准的扩展包可以, 比如, JavaServlet, Java3D 等等. 可以提个 建议, 加一个环境变量, 比如叫 JARPATH, 指定一个目录, 专门存放用户的 jar zip 省的是不能运行正确的, 然后把 tool.jar 放入 CLASSPATH 后工作正常. 现在作测试, 去掉仍然是正确的. 经过多次测试, 发现如果原来曾装过 jdk 的都很好, 没有装过的 |
呼呼 |
二, 包 (package) Java 中的 "包" 是一个比较重要的概念, package 是这样定义的: Definition: A package is a collection of related classes and interfaces that provides access protection and namespace management. 也就是: 一个包就是一些提供访问保护和命名空间管理的相关类与接口的集合. 使用包的目的就是使类容易查找使用, 防止命名冲突, 以及控制访问. 这里我们不讨论关于包的过多的东西, 只讨论和编译, 运行, 类路径相关的东西. 至于包的其他内容, 请自己查阅相关文档. 简单一点来说, 包就是一个目录, 下面的子包就是子目录, 这个包里的类就是 这个目录下的文件. 我们用一个例子来说明. 首先建目录结构如下: PackageTest/source/, 以后根目录指的是 PackageTest 目录, 我们的源程序放在 source 目录下. 源程序如下: PackageTest.java package pktest; import pktest.subpk.*; public class PackageTest { private String value; public PackageTest(String s) { value = s; } public void printValue() { System.out.println("Value of PackageTest is " + value); } public static void main(String[] args) { PackageTest test = new PackageTest("This is a Test Package"); test.printValue(); PackageSecond second = new PackageSecond("I am in PackageTest"); second.printValue(); PackageSub sub = new PackageSub("I am in PackageTest"); sub.printValue(); System.exit(0); } } PackageSecond.java package pktest; public class PackageSecond { private String value; public PackageSecond(String s) { value = s; } public void printValue() { System.out.println("Value of PackageSecond is " + value); } } PackageSub.java package pktest.subpk; import pktest.*; public class PackageSub { private String value; public PackageSub(String s) { value = s; } public void printValue() { PackageSecond second = new PackageSecond("I am in subpackage."); second.printValue(); System.out.println("Value of PackageSub is " + value); } } Main.java import pktest.*; import pktest.subpk.*; public class Main() { public static void main() { PackageSecond second = new PackageSecond("I am in Main"); second.printValue(); PackageSub sub = new PackageSub("I am in Main"); sub.printValue(); System.exit(0); } } 其中, Main.java 是包之外的一个程序, 用来测试包外的程序访问包内的类, PackageTest.java 属于 pktest 这个包, 也是主程序. PackageSecond.java 也 属于 pktest, PackageSub 属于 pktest 下的 subpk 包, 也就是 pktest.subpk. 详细使用情况, 请参看源程序. 好了, 先把源程序都放在 source 目录下, 使 source 成为当前目录, 然后编 译一下, 呵呵, 出错了, Main.java:1: Package pktest not found in import. import pktest.*; 这里涉及到类路径中包是怎么查找的, 前面我们做了一点假设: "只要包含了 这个类就算找到了这个类", 现在就有问题了. 其实 jdk 的 工具 javac java javadoc 都需要查找类, 看见目录, 就认为是包的名字, 对于 import 语句来说, 一个包对应一个目录. 这个例子中, import pktest.*, 我们知道类路径可以包 含一个目录, 那么就以那个目录为根, 比如有个目录 /myclass, 那么就会在查找 /myclass/pktest 目录及其下的类. 所有的都找遍, 如果没有就会报错. 由于现在 的类路径只有当前目录, 而当前目录下没有 pktest 目录, 所以就会出错. 类路径 还可以包含 .jar .zip 文件, 这些就是可以带目录的压缩包, 可以把 .jar .zip 文件看做一个虚拟的目录, 然后就和目录一样对待了. 好了, 应该知道怎么做了吧, 修改后的目录结构如下: PackageTest | |__source Main.java | |__pktest PackageTest.java PackageSecond.java | |__subpk PackageSub.java 然后重新编译, 运行, 哈哈, 通过了. 我们再来运行一下 PackageTest. [source]$ java pktest/PackageTest 怎么又出错了? Exception in thread "main" java.lang.NoClassDefFoundError: pktest/PackageTes t 是这样的, java 所要运行的是一个类的名字, 它可不管你的类在什么地方, 就象 我们前面所讨论的一样来查找这个类, 所以它把 pktest/PackageTest 看成是一个类的 名字了, 当然会出错了, 应该这么做, 的, javac 只编译, 不运行, 查找类也只有在源文件中碰到 import 时才会做, 与源文 好好地搁在这个目录里面. adding: pktest/PackageTest.class(in = 1041) (out= 602)(deflated 42%) |
呼呼 |
小结: 这篇文章中, 我们讨论了 java 中的 class path, package, jar 等基本但比较 重要的东西, 主要是 class path. 并不是简单的一份 CLASSPATH 的完全功略, 而是 试图让读者明白其原理, 自己思考, 自己动手. 其实大多数东西都在 sun 的 java doc 中都有, 我只不过结合例子稍微谈了一下, 希望能有所帮助. 由于条件所限, 只测试了 jdk1.2.2 在 98 及 linux 的情况, 其他版本的 jdk 和平台请大家自己测试, 错误在 其所在的目录. |