是否可以在现有实例上调用构造函数?

2024-02-13

据了解,使用sun.misc.Unsafe#allocateInstance无需调用任何类构造函数即可创建对象。

是否可以做相反的事情:给定一个现有实例,调用它的构造函数?


澄清:这不是我在生产代码中要做的事情的问题。我对 JVM 内部结构和仍然可以完成的疯狂事情感到好奇。欢迎特定于某些 JVM 版本的答案。


JVM §2.9 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9禁止在已初始化的对象上调用构造函数:

实例初始化方法只能在 Java 内部调用 虚拟机通过invokespecial指令,以及 它们只能在未初始化的类实例上调用。

然而,它仍然是技术上可行在初始化对象上调用构造函数JNI. 调用空方法 https://docs.oracle.com/javase/9/docs/specs/jni/functions.html#calltypemethod-routines-calltypemethoda-routines-calltypemethodv-routines函数之间没有区别<init>和普通的 Java 方法。此外,JNI 规范暗示CallVoidMethod may用于调用构造函数,尽管它没有说明是否必须初始化实例:

当这些函数用来打电话私有方法和构造函数,方法 ID 必须派生自 obj 的真实类,而不是其超类之一。

我已经验证以下代码在 JDK 8 和 JDK 9 中都可以工作。JNI 允许你做不安全的事情,但是你不应该依赖在生产应用中对此进行讨论。

构造函数调用器.java

public class ConstructorInvoker {

    static {
        System.loadLibrary("constructorInvoker");
    }

    public static native void invoke(Object instance);
}

构造函数Invoker.c

#include <jni.h>

JNIEXPORT void JNICALL
Java_ConstructorInvoker_invoke(JNIEnv* env, jclass self, jobject instance) {
    jclass cls = (*env)->GetObjectClass(env, instance);
    jmethodID constructor = (*env)->GetMethodID(env, cls, "<init>", "()V");
    (*env)->CallVoidMethod(env, instance, constructor);
}

测试对象.java

public class TestObject {
    int x;

    public TestObject() {
        System.out.println("Constructor called");
        x++;
    }

    public static void main(String[] args) {
        TestObject obj = new TestObject();
        System.out.println("x = " + obj.x);  // x = 1

        ConstructorInvoker.invoke(obj);
        System.out.println("x = " + obj.x);  // x = 2
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以在现有实例上调用构造函数? 的相关文章

随机推荐