为JNI控制的字段选择哪种可见性?

时间:2013-04-12 11:01:08

标签: java java-native-interface

我有一个Java类,它包含一个仅由本机JNI方法使用的本机句柄指针。让我们使用这个类(在http://thebreakfastpost.com/2012/01/23/wrapping-a-c-library-with-jni-part-1/找到)作为例子:

public class Plugin
{
    private long nativeHandle;

    protected Plugin(long handle) {
        nativeHandle = handle;
    }

    public native String getIdentifier();
    public native String getName();
    public native String getDescription();
    public native int getPluginVersion();

}

所以这个例子中的句柄是私有的。 JNI并不关心能见度。但像Eclipse中的那个源代码分析器抱怨该领域,因为它未被使用。 Eclipse无法知道有一些JNI代码访问此字段。

将字段设置为protected或public也是一个坏主意,因为可以从外部(直接或通过扩展类)修改句柄,从而导致崩溃。 Package-private并不是那么糟糕,但是像checkstyle这样的源代码分析器的默认设置会抱怨糟糕的编程风格。

当然,我可以添加一个@SuppressWarnings("unused")注释来消除日食警告,或者我可以添加一些注释,以便checkstyle忽略该问题或完全禁用checkstyle中的检查。但我不确定这是否需要,或者我是否只是做错了。

对于使用JNI代码的类中的本机句柄的可见性,是否有一些最佳实践?或者也许它们可以在某种程度上完全避免在Java代码中使用?

3 个答案:

答案 0 :(得分:1)

看看java.lang.Thread src

/**
 * Dispatch an uncaught exception to the handler. This method is 
 * intended to be called only by the JVM.
 */
private void dispatchUncaughtException(Throwable e) {
    getUncaughtExceptionHandler().uncaughtException(this, e);
}

Eclipse会抱怨未使用的方法,它仍然是私有的,注释有助于理解原因。

@SuppressWarnings("unused")是个好主意IMO

答案 1 :(得分:0)

除了禁用警告之外,我通常会尝试添加一个单元测试来检查字段的值。例如您可以检查它是非零并且对于不同的插件是不同的。

答案 2 :(得分:0)

嗯......也许我找到了另一种选择。那么,实际上有两种选择。两者都只是将私有值用于实际目的,因此代码分析器没有理由抱怨未使用的代码。

第一种方法是使用hashCodeequals中的原生句柄。这适用于此本机句柄是某种主键(例如,设备句柄)的对象。它对于使用其他数据来识别对象更有意义的对象不起作用(例如,用户对象可能已经有用户ID)。

public final Device
{
    /** The device handle. Set by native code. */
    private long handle;

    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (this.handle ^ (this.handle >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj) return true;
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        Device other = (Device) obj;
        if (this.pointer != other.pointer) return false;
        return true;
    }    
}

第二种选择只是为本机句柄提供一个getter。返回它是无害的,因为它仍然无法从外部修改。如果有人想编写自定义JNI代码,使用本机指针直接使用本机C API访问对象而不是使用Java API,它甚至可能很有用:

public final Device
{
    /** The device handle. Set by native code. */
    private long handle;

    public long getHandle()
    {
        return this.handle;
    }
}