有没有办法取消定义和重新定义 class 加载程序的 class?

Is there a way to undefine and redefine a class of a class loader?

有没有一种方法可以取消定义和重新定义 class 加载程序的 class 以及编译的另一个运行时 class?

不,没有办法取消定义 class 并重新定义它。

最接近的方法是创建一个新的 classloader 并使用它来加载 class 的新版本。 "hot loading"就是这样实现的。

但是,从 Java 运行时类型系统的角度来看,您实际上是在创建一个新类型。 (JLS 表示具有相同完全限定名称和不同 class 加载器的两个 class 是不同类型。)

备注:

  • 同时拥有一个类型的多个版本会导致不直观的运行时类型错误。

  • 你需要注意2个class加载器之间的关系。如果新的以旧的为父,事情会变得很乱。

  • 这种事情会导致一些相当隐蔽的内存泄漏。虽然 ClassClassLoader 对象可以被垃圾收集,但 classloader、classes 和实例之间存在一些复杂的(隐藏的)依赖关系,这意味着单个可达实例可以导致 classloader 及其所有已加载的 classes 仍然可以访问。


为什么没有办法呢?

一个原因是,它会在 JVM 的运行时类型安全性方面造成巨大的损失。考虑以下序列。

  1. 加载以下class

      public class Sneaky {
          public long x = 42;
      }
    
  2. 创建实例

      Sneaky s = new Sneaky();
    
  3. 将class重新定义为新版本

      public class Sneaky {
          public String x;
      }
    
  4. 尝试使用我们之前创建的对象的x字段

      System.out.println(s.x.length());
    

    会发生非常糟糕的事情....