在 VM 加载接口时调用一些代码



在普通的Java类中,当VM加载一个类时,它会调用clinit方法,所以我想知道当VM加载接口时,它可以调用一些代码吗?

比如class B implements Anew B()、VM调用Bclinit,VM会怎么处理AA中我可以插入一些代码吗System.out.println("hello")

直接不是,Java 接口不应该包含任何代码,即使你现在可以有默认方法。以下代码将无法编译:

interface Foo {
init {
System.out.println("Loading Foo...");
}
}

但是,接口可以包含静态字段:

interface Foo {
static class FooLoader {
private static Object init() {
System.out.printf("Initializing %s%n", Foo.class);
}
}
Object NULL = FooLoader.init();
}

同样,它可能有效,但是:

  1. 通过反射,仍然可以调用init()方法,因此可以调用两次
  2. 代码不是在加载时真正调用的,而是在初始化时调用的。要理解,我的意思是检查这个简单的主:

    System.out.println("START"(; System.out.println(Foo.class(; System.out.println("END"(;

只要您不访问静态成员,Java 接口就不会初始化(参见 JVM 规范的 §5.5(

因此,要真正捕获加载时间,您可以使用定制类装入器或检测 API。

在接口中static {}块是不可能的。但是,如果您真的确定在加载接口时需要调用一些代码,则可以使用自定义类加载器,它将挂接您的接口加载并对其执行一些操作

下面是一个示例:

static class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("test.Test1")) {
... do whatewer you need on loading class/interface...
}
return getParent().loadClass(name);
}
}
}

如何在java中替换正在运行的应用程序中的类?

还有非常有用的教程:https://zeroturnaround.com/rebellabs/reloading-objects-classes-classloaders/

正如另一个答案中提到的,接口中不能有静态部分。但是,您可以使用静态方法和静态最终字段。您可以组合两者以进行调试。

interface TestInterface {
int dummy = init();
static int init() {
System.out.println("Loaded TestInterface");
return 1;
}
}

最新更新