URLClassLoader中指定目录和jar的问题

测试用的是jdk1.6.0_16. 项目的结构图:

  
                                URLClassLoader中指定目录和jar的问题

src:源码

classes:编译后的文件

lib:junit

urlclassloaderpath:测试过程中要从这里加载类

编译和运行(都是在classloader目录下):

编译:javac -encoding utf-8 -d classes -cp lib\junit-4.7.jar src\urlclassloader\URLClassLoaderTest.java
运行:java -cp classes;lib\junit-4.7.jar org.junit.runner.JUnitCore urlclassloader.URLClassLoaderTest

 

 

问题的来源,先看下面的code:

 

try {
	System.out.println("==========test2=========");
	URL[] urls = new URL[] {
			new URL("file:/" + System.getProperty("user.dir") + "/urlclassloaderpath")
			// new URL("file:/" + System.getProperty("user.dir") + "/urlclassloaderpath/")
	};
	
	for(URL u : urls) {
		System.out.println(u.toString());	
											
	}
	
	URLClassLoader ul = new URLClassLoader(urls);

	Class<?> c = ul.loadClass("hello.HelloWorld");
	System.out.println(c);

	c = ul.loadClass("urlclassloader.test.Test");
	System.out.println(c);
	System.out.println("==========test2=========" + rt);
} catch (Exception e) {
	System.out.println("test2():" + e + rt);
}

上面的意思就是从urlclassloaderpath下加载hello.HelloWorld这个类, 目录下也的确存在hello包和HelloWorld类。如果使用的是:new URL("file:/" + System.getProperty("user.dir") + "/urlclassloaderpath"),那么运行的时候会出现异常:java.lang.ClassNotFoundException。如果使用的是:new URL("file:/" + System.getProperty("user.dir") + "/urlclassloaderpath/") 则是OK的。郁闷的地方来了,指定classes目录时,无论是否在最后加"/"都是没有问题的,换成urlclassloaderpath目录怎么就不行了?

 

可以先查看一下URLClassLoader类的API(中文的), 是这么说的:该类加载器用于从指向 JAR 文件和目录的 URL 的搜索路径加载类和资源。这里假定任何以 '/' 结束的 URL 都是指向目录的。如果不是以该字符结束,则认为该 URL 指向一个将根据需要打开的 JAR 文件。

不过从运行的结果来看,貌似不是很对。

 

再看刚刚那个程序, 下面还加载了:c = ul.loadClass("urlclassloader.test.Test"); 在URL中我们并没有指定classes目录, 但是加载urlclassloader.test.Test缺少没有任何问题的。其实这里可以这么思考下:运行的时候指定的classpath是classes,那么从这个目录下加载当然是没有问题的。这样的话就能够说的通了。

 

 

再来看下加载jar包中的类. 只是指定了目录,而没有指定具体的jar包。

		try {
			URL[] urls = new URL[] {
					new URL("file:" + System.getProperty("user.dir") + "/classes/")
			};
			
			for(URL u : urls) {
				System.out.println(u.toString());
			}	
			
			// 从jar文件中加载一个类
			URLClassLoader ul = new URLClassLoader(urls);
			Class<?> c = ul.loadClass("test.classpath.jar.ClasspathJarFile");
			
			System.out.println(c);	
			System.out.println("==========test=========" + rt);
		} catch (Exception e) {
			System.out.println("test() : " + e + rt);
		}

运行上面的程序,报的是java.lang.ClassNotFoundException。 如果改成:

new URL("file:" + System.getProperty("user.dir") + "/classes/classpath.jar")

   指定了具体的jar包,则是没有问题的。

其实这个和我们的命令行差不多,在我们指定-cp的时候必须要指定具体的jar包,而不能只指定目录。

完整的测试程序见附件或者https://github.com/yklovejava/yklovejava/tree/master/jvm/classloader

 

总结:测试完后就明白了

 

你可能感兴趣的:(ClassLoader)