JVM启动后Java类路径是最终的吗?

Jen*_*ens 22 java classpath classloader

我最近读了很多关于Java类加载过程的内容.我经常遇到这样的文本,声称在运行时期间无法在类路径中添加类并在没有类加载器hackery(URLClassLoaders等)的情况下加载它们.

据我所知,类是动态加载的.这意味着它们的字节码表示仅在需要时加载并转换为java.lang.Class对象.

所以,在JVM启动后,不应该可以在类路径中添加JAR或*.class文件并加载这些类,只要它们尚未加载?(要清楚:在这种情况下,类路径只是文件系统上的文件夹."添加JAR或*.class文件"只是意味着将它们放在这个文件夹中.)

如果没有,这是否意味着在JVM启动时搜索类路径,并且找到的类的所有完全限定名称都缓存在内部"列表"中?

如果你能指出我的答案中的一些消息来源,你会很高兴.最好的SUN文档:Sun JVM Spec.我已阅读规范,但无法找到有关类路径的任何内容,以及它是否已在JVM启动时完成.

PS

这是一个理论问题.我只想知道是否有可能.我想实现没有任何实际意义.只有我对知识的渴望:)

Yis*_*hai 6

这里有两个混合的概念:类路径和类路径中的类文件.

如果将类路径指向某个目录,则通常没有问题将文件添加到目录并将其作为类路径的一部分进行拾取.由于类路径中所有类的潜在大小,现代JVM在启动时加载它们并不是真的可行.但是它的价值有限,因为它不包含Jar文件.

但是,在运行的JVM上更改类路径本身(搜索哪些目录,jar等)将在很大程度上取决于实现.据我所知,在标准的Sun JVM上,没有记录(如保证工作)的方法来实现这一点.

一般来说,如果这是你需要做的事情(有一个在运行时更改的动态类路径)那么你想要实现一个ClassLoader,如果没有其他原因,只能将它扔掉并创建一个新的如果需要卸载那些类,则不再引用它们.

但是,对于少量动态加载,有更好的方法.在Java 1.6中,您可以在目录(*.jar)中指定所有jar文件,这样您就可以告诉用户将其他库放在指定位置(尽管它们必须在启动时存在).

您还可以选择在类路径中包含jar文件或其他位置,即使您不需要它,也可以选择将某个可选jar或资源文件放在那里(例如日志配置文件).

但是,如果您需要严格的动态类加载,尤其是在应用程序运行时卸载,则需要使用Classloader实现.


Jen*_*ens 6

由于没有人可以给出我明确的答案或链接到文档的相应部分,我自己提供答案.不过,我要感谢所有试图回答这个问题的人.

简短回答:

JVM启动时,类路径不是最终的.

实际上,您可以在JVM启动后将类放在类路径中,然后加载它们.


答案很长:

为了回答这个问题,我去了用户未知的建议并写了一个小测试程序.

基本的想法是有两个类.一个是实例化第二个类的主类.在启动时,第二个类不在类路径上.cli程序启动后,它会提示你按回车键.在按Enter之前,您将复制类路径上的第二个类.按Enter后,第二个类被实例化.如果类路径在JVM启动时是最终的,则会抛出异常.但事实并非如此.所以我假设类路径在JVM启动时不是最终的.

以下是源代码:

JVMTest.java

package jvmtest;

import java.io.Console;
import jvmtest.MyClass;

public class JVMTest {
  public static void main(String[] args) {
    System.out.println("JVMTest started ...");

    Console c = System.console();
    String enter = c.readLine("Press Enter to proceed");
    MyClass myClass = new MyClass();
    System.out.println("Bye Bye");
  }
}
Run Code Online (Sandbox Code Playgroud)

MyClass.java

package jvmtest;

public class MyClass {
  public MyClass() {
    System.out.println("MyClass v2");
  }
}
Run Code Online (Sandbox Code Playgroud)

文件夹结构如下所示:

jvmtest/
  JVMTest.class
  MyClass.class
Run Code Online (Sandbox Code Playgroud)

我用这个命令启动了cli程序:

> java -cp /tmp/ jvmtest.JVMTest
Run Code Online (Sandbox Code Playgroud)

如你所见,我在/ tmp/jvmtest中有我的jvmtest文件夹.你显然必须根据你放置类的位置来改变它.

以下是我执行的步骤:

  1. 确保只有JVMTest.class在jvmtest中.
  2. 使用上面的命令启动程序.
  3. 只是为了确保按回车键.您应该看到一个Exception告诉您没有找到任何类.
  4. 现在再次启动程序.
  5. 程序启动后,系统提示您按Enter键将MyClass文件复制到jvmtest文件夹中.
  6. 按enter键.你应该看到"MyClass v1".

补充说明:

当我在一个jar中打包MyClass类并运行上面的测试时,这也有效.

我在运行Mac OS X 10.6.3的Macbook Pro上运行了这个

> Java -version
Run Code Online (Sandbox Code Playgroud)

结果是:

java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)
Run Code Online (Sandbox Code Playgroud)

  • 你的答案和"解决方案"具有误导性.您没有修改类路径,您修改了类路径的_contents_.此外,这将被视为一种不好的做法. (8认同)