编译时和运行时Java中类加载器的顺序

时间:2018-06-30 02:33:25

标签: java classloader classloading

我在Java下创建了具有合格名称java.lang.String的类。

package java.lang;

public class String {
    public int getValue() {
        return 42;
   }
}

在Main Class中,我添加了以下代码。

public class Main {

    public static void main(String[] args) {
        String s = new String();
        System.out.println(s.getValue());
    }
}

代码编译就好了。当我运行代码时,它失败并显示以下错误。

 Exception in thread "main" java.lang.NoSuchMethodError:    java.lang.String.getValue()I
at com.Main.main(Main.java:12)

我了解了java.lang.String是在运行时由Bootstrap类加载器从rt.jar文件加载的。

因此,我认为在编译时和运行时,类加载的顺序应有所不同。您能否在编译时和运行时给出类加载的顺序。

1 个答案:

答案 0 :(得分:2)

首先,此测试在Java 9或更高版本中不起作用。尝试编译String类将产生此错误:

java/lang/String.java:1: error: package exists in another module: java.base
package java.lang;
^

在Java 8上,我得到了您看到的行为。假设经过调整的String类在同一源代码树中,则Main类会编译,但是在您尝试运行它时会给出异常。

这似乎被报告为bug 4929425。解决方案是这是一个文档错误,他们澄清了javac命令的文档……虽然可能还不够。

无论如何,有一个区别,这是一个微妙的区别。

java命令仅按以下顺序搜索:

  • 引导类路径
  • 扩展目录
  • classpath

javac命令首先搜索源目录。如果在该目录中找到源文件,它将在相同位置查找相应的类文件,并(如有必要)对其进行编译或重新编译。如果未找到源文件,则它将按照上述java的描述在类路径中搜索类文件。

请注意,您需要非常仔细地阅读javac手动输入才能理解这一点。很容易错过。 (https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#searching

(IMO,他们可以使手册页面更清晰。但是,这种不一致仅在您尝试覆盖引导程序类路径或扩展目录中的某个类时才有所不同。并且您以错误的方式这样做。基本上,这是一个极端情况。清楚地记录模糊的极端情况的问题是,最终会使正常情况下的文档更加混乱。)