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

JVM启动后Java类路径是最终的吗?,java,classpath,classloader,Java,Classpath,Classloader,我最近读了很多关于Java类加载过程的书。我经常遇到一些文本,声称在运行时不可能在没有类装入器黑客(URLClassLoaders等)的情况下将类添加到类路径并装入它们 据我所知,类是动态加载的。这意味着它们的字节码表示仅在需要时加载并转换为java.lang.Class对象 那么,在JVM启动并加载这些类之后,如果它们还没有被加载,那么是否可以在类路径中添加一个JAR或*.class文件?(需要明确的是:在本例中,类路径只是文件系统上的文件夹。“添加JAR或*.class文件”只意味着将它们放

我最近读了很多关于Java类加载过程的书。我经常遇到一些文本,声称在运行时不可能在没有类装入器黑客(URLClassLoaders等)的情况下将类添加到类路径并装入它们

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

那么,在JVM启动并加载这些类之后,如果它们还没有被加载,那么是否可以在类路径中添加一个JAR或*.class文件?(需要明确的是:在本例中,类路径只是文件系统上的文件夹。“添加JAR或*.class文件”只意味着将它们放在这个文件夹中。)

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

如果你能在你的答案中给我指出一些来源,那就太好了。最好是官方SUN文档:。我已经阅读了规范,但找不到关于类路径的任何信息,也找不到它是否在JVM启动时最终确定

附言


这是一个理论问题。我只是想知道这是否可能。我不想实现任何实际的目标。这只是我对知识的渴求:)

我只能根据我记忆中的十年前入侵非sun JVM的经历来评论,但作为一种效率衡量标准,它确实在启动时扫描了整个类路径。找到的所有类的名称连同它们的位置(目录或zip/jar文件)一起添加到内部哈希表中。然而,那是十年前的事了,考虑到磁盘和内存体系结构是如何演变的,我不禁怀疑在大多数设置中这样做是否仍然合理。

我认为类路径是静态的,更改文件的结果是未定义的

如果您真的希望能够在运行时添加和移除类,请考虑在自己的类加载器中这样做。这就是web容器所做的

那么,是否可以添加一个 JAR或*.class文件到类路径 JVM启动后

将JAR和目录添加到类路径,而不是类。这些类位于目录或jar中

如果不是,这是否意味着 在JVM启动时搜索类路径 以及 找到的类缓存在 内部“名单”


这很容易测试:设置类路径,启动程序,将一个新类移动到CP中,从程序中调用'class.forName(“NewClass”)。它找到新类了吗

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

如果您将类路径指向一个目录,那么在目录中添加一个文件并将其作为类路径的一部分拾取通常不会有问题。由于类路径中所有类的潜在大小,现代JVM在启动时将它们全部加载是不可行的。然而,这是有限的价值,因为它将不包括Jar文件

但是,在运行的JVM上更改类路径本身(搜索目录、JAR等)将在很大程度上取决于实现。据我所知,在标准Sun JVM上,没有实现这一点的文档化方法(如“保证工作”)

一般来说,如果这是您需要做的事情(有一个在运行时改变的动态类路径),那么您希望实现一个类加载器,如果没有其他原因,只是为了能够将它扔掉并创建一个新的类加载器,在需要卸载这些类时不再引用这些类

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

您还可以选择在类路径中包含一个jar文件或其他位置,即使您不需要它,作为占位符,以便有人将可选的jar或资源文件(如日志配置文件)放在那里


但是,如果您需要严重的动态类加载,特别是在应用程序运行时卸载,则需要类加载器实现。

因为没有人能给我一个明确的答案,也没有人能给我一个指向文档相应部分的链接,所以我自己提供答案。然而,我要感谢所有试图回答这个问题的人

简短答复:

类路径在JVM启动时不是最终路径。

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


长答覆:

为了回答这个问题,我按照建议写了一个小测试程序

基本思想是有两个类。一个是实例化第二个类的主类。启动时,第二个类不在类路径上。cli程序启动后,将提示您按enter键。在按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");
  }
}
MyClass.java

package jvmtest;

public class MyClass {
  public MyClass() {
    System.out.println("MyClass v2");
  }
}
文件夹结构如下所示:

jvmtest/
  JVMTest.class
  MyClass.class
我使用以下命令启动cli程序:

> java -cp /tmp/ jvmtest.JVMTest
如您所见,我的jvmtest文件夹位于/tmp/jvmtest中。显然,你必须根据你把类放在哪里来改变这一点

下面是我执行的步骤:

  • 确保JVMTest中只有JVMTest.class
  • 用上面的命令启动程序
  • 只是为了确保按下回车键。您应该会看到一个异常,告诉您找不到类
  • 现在开始t
    > Java -version
    
    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)
    
    public class Launcher
    {
     <...>
     static class AppClassLoader
        extends URLClassLoader
      {
        final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);
    <...>
    
    protected Class<?> findClass(final String paramString)
        throws ClassNotFoundException
      {
        <...>
              String str = paramString.replace('.', '/').concat(".class");
              Resource localResource = URLClassLoader.this.ucp.getResource(str, false);
      <...>
    
    In [78]: jpype.org=jpype._jpackage.JPackage("org")
    
    In [79]: jpype.org.dom4j.Entity
    Out[79]: jpype._jclass.org.dom4j.Entity