关于java 找不到类错误 的一些小实验
(2011-5-7 7:33am by 黄金龙 )
图1
注意classpath 变量并没有设置 但是一样可以正常运行
在这个程序的基础之上 我们通过逐步更改来探究 package import 以及 classpath 的含义
1:在源程序 Hello.java 加入 package tools ;
图 2
图 3
编译通过了 但是在当前目录下是无法运行的。
这是因为package tools ;已经指定 hello class 是属于 tools 包的 你必须把编译后生成的 hello.class 文件放到 tools 的目录里边去。好我们来新建一个目录 tools ,并把生成的 hello.class 文件放进去。如图
图 4
现在我们来运行
J ava tools.Hello 或者 java tools/Hello 都将得到期望的结果。可以自己试一下。
运行命令cd ..
退到上层目录,试着调用hello. C lass 。
图 5
注意classpath 并没有被设置 这个时候系统报错 NoClassDefFoundError
现在是classpath 发挥威力的地方了 。讲 tools 目录加入到 classpath 。在看看
图 6
G ood! 现在明白了吧! classpath 就是告诉系统到哪里去找我们的 class
现在你可以到任何目录下java tools .Hello 都将得到期望的结果 但是 java 后边必须接 Hello 的全名 即包括的他的包名(当然在一个 java 源文件中可以用 import 来引用包 这样在就不用写出全名了)。由于 class 所属的包是在源文件中写死的,我们不能单从 Hello.class 文件本名来查看它所属的
图 7
包, 下面我们来看一种方法看看他到底是属于哪个包
看到了吧,你使用package 来编译一个 java 文件的时候 真正的类是 包名 . 类名,系统也是通过这个全名来找这个类的。还有你一定要把你编译的 java 文件放到 和你指定的 package
相应的目录结构中去,比如 若是 package a.b.c; 则 这个文件必须放到 a/b/c/ (注意 windows 下的目录分隔符是 ’ / ’ linux的是 ’ / ’ )看下图
当前目录已经被默认加入到class 的搜索中去了 不需要在 classpath 变量中显示指定。但是你若是要指定 classpath 就一定要把 .; 等加上。
你若在使用的三方给的包(你自己写的也是一样)的时候千万不要改变它里边的目录结构,否则会出现出现 找不到 类的错误 ,而它“明明就那里”。你大概不希望用javap 来查看每一个 class 文件所属的包吧。
注:若用set 命令来是制定环境变量 只适用于当前的 cmd 窗口 要永久更改 环境变量就要在系统属性——高级——环境变量中更改。
总结 :
(1) 当你执行 java a.b.test 的时候 jvm 是通过 classpath 变量所指定的目录下寻找 a 目录,进入 a 目录,寻找 b 目录,进入 b 目录再寻找 test.class 文件 然后查看这个文件内的类是不是 a.b.test (通过 javap 来查看,前面有例子 ,图 7 ),如果是,则载入,不存在或不是则错误。另外可一通过代-verbose 参数来运行 java 可以看到整个的载入类的过程,例如: java -verbose a.test 他的输出很惊人(如果执行成功的话)脑袋都大了 ,但是不用担心,我们写的类基本上都是在最后载入的,因此只要看最后几行输出就好,(看下图,注意最后倒数 3 行 , 这是 java – verbose tools.Hello 的输出)
2
CLASSPATH的陷阱
P.java文件存在一个非常有趣的陷阱。特别是对于早期的 Java 实现方案来说,类路径的正确设定通常都是很困难的一项工作。编写这本书的时候,我引入了 P.java 文件,它最初看起来似乎工作很正常。但在某些情 况下,却开始出现中断。在很长的时间里,我都确信这是 Java 或其他什么在实现时一个错误。但最后,我终于发现在一个地方引入了一个程序(即第 17 章要说明的 CodePackager.java ),它使用了一个不同的类 P 。 由于它作为一个工具使用,所以有时候会进入类路径里;另一些时候则不会这样。但只要它进入类路径,那么假若执行的程序需要寻找com.bruceeckel.tools 中的类, Java 首先发现的就是 CodePackager.java 中的 P 。此时,编译器会报告一个特定的方法没有找到。这当然是非常令人头疼的,因为我们在前面的类 P 里明明看到了这个方法,而且根本没有更多的诊断报告可为我们提供一条线索,让我们知道找到的是一个完全不同的类(那甚至不是 public 的)。乍一看来,这似乎是编译器的一个错误,但假若考察 import 语句,就会发现它只是说: “ 在这里可能发现了 P” 。然而,我们假定的是编译器搜索自己类路径的任何地方,所以一旦它发现一个 P ,就会使用它;若在搜索过程中发现了 “ 错误的 ” 一个,它就会停止搜索。这与我们在前面表述的稍微有些区别,因为存在一些讨厌的类,它们都位于包内。而这里有一个不在包内的 P ,但仍可在常规的类路径搜索过程中找到。如果您遇到象这样的情况,请务必保证对于类路径的每个地方,每个名字都仅存在一个类。 (摘自 <thinking in java>第四版 5.1 )
相信都看的明白可以自己写点程序验证一下
E dited by 黄金龙
嘿嘿!!