JNI可以在初始化期间调用对象上的方法吗?

时间:2011-05-20 17:52:22

标签: java initialization java-native-interface final

java类的功能类似于以下

public class Foo {

    private final NativeCallbackHandler handler;

    public Foo(NativeCallbackHandler handler) {
        // I've shortened this for exposition, callSomeNativeMethod 
        // really happens in a superclass that I don't own (and is 
        // part of the lib that gives me the native part)
        callSomeNativeMethod();
        this.handler = handler;
    }

    public void handleNativeCallback(Object args) {
        this.handler.callback(args);
    }

    private native int callSomeNativeMethod();
}

您可以假设本机方法执行的操作可能会导致本机代码调用handleNativeMethod

我有2个相关问题

  1. 我相信本机代码必须调用此对象的句柄,并且还调用GetMethodID来访问要调用的方法,该本机代码是否可以在之前调用 strong>对象是否已完全初始化?
  2. 如果可以的话,未初始化的最终字段的语义是什么?
  3. 如果1为是,那么我希望2能够在访问它时爆炸,因此我想我们需要将其设为AtomicReference才能安全地访问它而不会爆炸。

    注意我无法控制本机库的行为。

2 个答案:

答案 0 :(得分:3)

看起来有可能。本机代码不会强制执行final限制。

来自http://java.sun.com/docs/books/jni/html/pitfalls.html#36197

  

10.9违反访问控制规则

     

JNI不强制执行class,field,   和方法访问控制限制   可以在Java上表达   编程语言水平通过   使用修饰符如private和   最后。可以写原生的   用于访问或修改字段的代码   即使这样做也是对象   Java编程语言水平会   导致IllegalAccessException。   JNI的放纵是有意识的   设计决定,鉴于原生   代码可以访问和修改任何内存   无论如何,在堆中的位置。

     

绕过的本机代码   源语言级访问检查   可能会产生不良影响   程序执行。例如,一个   如果a,可能会产生不一致   native方法修改final字段   在即时(JIT)编译器之后   已经内联访问该字段。   同样,本机方法不应该   修改不可变对象,如   实例中的字段   java.lang.String或java.lang.Integer。   这样做可能会导致破损   Java平台中的不变量   实施

当您访问未初始化的最终引用时,这不会定义行为,但我们可能会做出相当不错的猜测。

就个人而言,我会尝试通过以下方式避免这个问题:

  • 确保在回调之前初始化所有内容
  • 在回调期间不执行任何操作,直到设置了初始化完成的标志。

答案 1 :(得分:2)

从超类构造函数调用handleNativeCallback将导致NullPointerException,因为它在设置处理程序之前被调用。调用是由JNI还是纯Java代码没有区别。