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

4
一个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
我有两个相关的问题:
1. 我认为本地代码必须在该对象上拥有一个句柄,并调用GetMethodID来获取访问要调用的方法的权限。那么,在对象完全初始化之前,本地代码能否调用该方法?
2. 如果可以,在未初始化的final字段上的语义是什么?
如果问题1的答案是肯定的,那么我期望问题2在访问时会崩溃,因此我想我们需要将其设置为AtomicReference以便安全地访问它而不会崩溃。
请注意,我无法控制本地库的行为。

1
你为什么在设置处理程序字段之前调用'callNativeMethod'方法? - Andrew
你不能只构建并运行它,看看结果吗?你似乎已经完成了90%的工作... - John Gardner
因为我不拥有本地库中的代码,这就是它可能的行为。问题在于它很难调用此方法(这是一个时间问题),我无法强制它这样做。它取决于网络中发生的各种事情以及某些消息何时以及以什么顺序到达,这意味着很难确定性地重新创建。因此,我需要知道是否存在问题,如果存在问题,则是什么问题。 - Matt
你拥有Foo吗?你能不能交换一下'callNativeMethod()'和'thisHandler = headler'这两行的顺序? - Andrew
@Andrew,我编辑了代码示例,试图让它更清晰,以便说明我为什么不能这样做。 - Matt
你最大的问题就是你已经描述过的那个。也就是在处理程序设置之前,会调用你的“handleNativeMethod”。此时该字段可能为空,你能做的最好的事情就是测试是否为空,并且不调用空处理程序字段。你可以编写一个测试用例来验证这种行为。 - Andrew
2个回答

3

看起来是可能的。本地代码不强制执行final限制。

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

10.9 违反访问控制规则

JNI 不强制执行类、字段和方法访问控制限制,这些限制可以通过 Java 编程语言级别的修饰符(例如 private 和 final)表达。即使在 Java 编程语言级别,访问或修改对象的字段会导致 IllegalAccessException,但仍然可以编写本地代码来访问或修改对象的字段。JNI 的宽容是一种有意的设计决策,因为本地代码可以访问和修改堆中的任何内存位置。

绕过源语言级别的访问检查的本地代码可能对程序执行产生不良影响。例如,如果本地方法在 JIT 编译器内联访问字段后修改 final 字段,则可能会创建不一致性。同样,本地方法不应修改不可变对象,例如 java.lang.String 或 java.lang.Integer 实例中的字段。这样做可能会导致 Java 平台实现中的不变量破坏。

这并没有定义当您访问未初始化的 final 引用时的行为,但我们可能可以猜到一个相当好的答案。

个人而言,我会尝试避免这个问题,具体方式为:

  • 确保在回调函数之前初始化所有内容
  • 在回调函数期间不做任何操作,直至标志位指示初始化完成。

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

+1,好观点 - 而且无论字段是否为最终字段都会发生。 这是一个纯Java示例:http://ideone.com/0HoFk。 - Andy Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接