首页 > 学院 > 开发设计 > 正文

类装入问题解密,第 3 部分: 处理更少见的类装入问题

2019-11-18 15:01:52
字体:
来源:转载
供稿:网友
这个四部分构成的文章系列研究 java™ 的类装入问题,帮助应用程序开发人员理解和调试可能碰到的问题。在第 3 部分中,来自 IBM Hursley 实验室的作者 Lakshmi Shankar 和 Simon Burns 在本系列前两部分的基础之上,具体介绍了不同种类的类装入问题,包括与类路径、类可视性和垃圾收集有关的问题。

本文是本系列中四篇文章的第三篇,它研究了在 Java 开发过程中的一些更复杂、更少见的类装入问题。造成这些问题的原因通常无法直接从症状得出;所以,解决起来既困难又费时。与本系列以前的文章一样,我们仍然提供示例来演示问题,然后讨论各种解决技术。

在开始这篇文章之前,应当熟悉类装入委托模型,以及类链接的阶段和过程。我们强烈建议您从阅读本系列的 第一篇文章 开始。

与类路径有关的问题

有一个非常简单的问题通常与用户设置的类路径有关。清单 1 和清单 2 中的示例演示了这个问题。

测试用例创建了两个类装入器,每个类装入器使用的类路径看起来相同。但是,有一个微小但是却重大的区别:一个类路径末尾有 /,而另一个没有。在这两个类路径中的一个名为 cp 的子目录中有一个类 Z(在清单 2 中)。两个类装入器都试图装入 Z


清单 1. ClasspathTest.java
import java.net.URL;import java.net.URLClassLoader;public class ClasspathTest {	    String userDir;    URL withSlash;    URL withoutSlash;    ClasspathTest() {        try {            userDir = System.getPRoperty("user.dir");            withSlash = new URL("file://C:/CL_Article/ClasspathIssues/cp/");            withoutSlash = new URL("file://C:/CL_Article/ClasspathIssues/cp");        } catch (Exception e) {            e.printStackTrace();        }    }    void run() {        try {            System.out.println(withSlash);            URLClassLoader cl1 = new URLClassLoader(new URL[] { withSlash });            Class c1 = cl1.loadClass("Z");            System.out.println("Class Z loaded.");            System.out.println(withoutSlash);            URLClassLoader cl2 = new URLClassLoader(new URL[] { withoutSlash });            Class c2 = cl2.loadClass("Z");            System.out.println("Class Z loaded.");        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        new ClasspathTest().run();    }}


清单 2. Z.java
public class Z {}

这个测试用例产生以下输出:

file://C:/CL_Article/ClasspathIssues/cp/Class Z loaded.file://C:/CL_Article/ClasspathIssues/cpjava.lang.ClassNotFoundException: Z    at java.net.URLClassLoader.findClass(URLClassLoader.java:376)    at java.lang.ClassLoader.loadClass(ClassLoader.java:572)    at java.lang.ClassLoader.loadClass(ClassLoader.java:504)    at ClasspathTest.run(ClasspathTest.java:28)    at ClasspathTest.main(ClasspathTest.java:36)

可以看到,传递给每个 URLClassloader 的参数略有不同。提供给第一个类装入器 cl1 的类路径末尾有 /。提供给第二个类装入器 cl2 的类路径末尾没有 /。这个区别是显著的,因为类装入器假设不以 / 结尾的路径指向的是 JAR 文件。只有以 / 结尾的路径才被假定为指向目录。

因为 cl1 的类路径被当作目录,所以这个类装入器能够找到在这个位置的类 Z,并能够装入它。cl2 的类路径被假定为 JAR 文件;这个类装入器不能发现类 Z ,因为没有这个文件。所以,cl2.loadClass() 抛出 ClassNotFoundException



发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表