是否可以在现有实例上调用构造函数? [英] Is it possible to call constructor on existing instance?

查看:132
本文介绍了是否可以在现有实例上调用构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

众所周知,使用sun.misc.Unsafe#allocateInstance可以创建一个对象而无需调用任何类构造函数.

It is known that using sun.misc.Unsafe#allocateInstance one can create an object without calling any class constructors.

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

Is it possible to do the opposite: given an existing instance, invoke a constructor on it?

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

Clarification: this is not the question about something I'd do in production code. I'm curious about JVM internals and crazy things that can still be done. Answers specific to some JVM version are welcome.

推荐答案

JVMS §2.9 forbids invocation of constructor on already initialized objects:

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

Instance initialization methods may be invoked only within the Java Virtual Machine by the invokespecial instruction, and they may be invoked only on uninitialized class instances.

但是,使用 JNI 在初始化的对象上调用构造函数仍然是技术上可行的. CallVoidMethod 函数在<init>和普通Java方法之间没有区别.此外,JNI规范暗示CallVoidMethod 可以用来调用构造函数,尽管它没有说明是否必须初始化实例:

However, it is still technically possible to invoke constructor on initialized object with JNI. CallVoidMethod function does not make difference between <init> and ordinary Java methods. Moreover, JNI specification hints that CallVoidMethod may be used to call a constructor, though it does not say whether an instance has to be initialized or not:

当这些功能用于调用私有方法和构造函数时,方法ID必须从obj的真实类派生,而不是其超类之一. /p>

When these functions are used to call private methods and constructors, the method ID must be derived from the real class of obj, not from one of its superclasses.

我已经验证了以下代码在JDK 8和JDK 9中均适用.JNI允许您执行不安全的操作,但是您不应在生产应用程序中依赖.

I've verified that the following code works both in JDK 8 and JDK 9. JNI allows you to do unsafe things, but you should not rely on this in production applications.

ConstructorInvoker.java

public class ConstructorInvoker {

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

    public static native void invoke(Object instance);
}

constructorInvoker.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);
}

TestObject.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
    }
}

这篇关于是否可以在现有实例上调用构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆