为什么 SIZE 常量仅@Native整数和多头?结论

2022-09-01 01:39:08

我理解@Native注释的使用。

指示可以从本机代码中引用定义常量值的字段。生成本机头文件的工具可以使用该批注作为提示,以确定是否需要头文件,如果需要,则应包含哪些声明。

但是,在阅读java源代码时,我注意到在类中,常量虽然不适用于浮点数,字节,双精度,短和字符。IntegerLongSIZE@Native

请注意,SIZE 常量表示用于表示实际值的位数。

public static final int SIZE = 8;//Byte
public static final int SIZE = 16;//Character
public static final int SIZE = 16;//Short
public static final int SIZE = 32;//Float
@Native public static final int SIZE = 32;//Integer
@Native public static final int SIZE = 64;//Long
public static final int SIZE = 64;//Double

编辑:我刚刚注意到这也适用于相同的类。MAX_VALUEMIN_VALUE


编辑 2 :我有空闲时间对此进行一些研究,并且查看Long,Float等类的头文件,我希望弄清楚这些常量不存在于其他头文件中,但不幸的是它们存在。

static const jint SIZE = 8L;//java/lang/Byte.h
static const jint SIZE = 16L;//java/lang/Character.h
static const jint SIZE = 16L;//java/lang/Short.h
static const jint SIZE = 32L;//java/lang/Float.h
static const jint SIZE = 32L;//java/lang/Integer.h
static const jint SIZE = 64L;//java/lang/Double.h
static const jint SIZE = 64L;//java/lang/Long.h

为什么 SIZE 常量仅@Native整数和多头?


答案 1

TLDR:跳到结论


为什么 SIZE 常量仅@Native整数和多头?

简史@Native

我在邮件列表上进行了一些搜索。我发现了一些有趣的事情。

首先,一个注释(1 2javax.tools.annotation.ForceNativeHeader被引入

以在类上触发 javah。

它由com.sun.tools.javac.processing.NativeapiVisitor使用。通过查看代码,我们可以看到,如果类声明了一些本机方法,或者如果类是带注释的,则会生成本机标头。@ForceNativeHeader

后来这个注释被重命名为 GenerateNativeHeader1 2)。

然后,将此注释添加到几个类型(特别是整数和长整)中,并带有一个中间注释:

/* No native methods here, but the constants are needed in the supporting JNI code */
@GenerateNativeHeader
public final class Long extends Number implements Comparable<Long> {...

但是通过添加此注释,它将从基本模块到包含javax.tools的模块添加了一个有问题的依赖项。因此,注释从 IntegerLong 中删除,这些文件被显式添加到构建过程中,因为标头不再是自动生成的...“(希望是暂时的)黑客攻击”。

因此,创建了一个新的注释,并在整数长整型中使用。注释设置为 .java.lang.annotation.NativeTargetType FIELD

注释应直接应用于需要导出的常量字段,而不是整个类。


这个东西的所有目的是:

javac可以为包含本机方法的类生成本机标头。

它是和IntegerLong

这是JEP 139的一部分:增强javac以提高构建速度

javah将自动在任何包含本机方法的类上运行,生成的C头将被放在(-h)头文件中。新的注记@ForceNativeHeader用于具有需要导出到 JNI 但没有本机方法的最终静态基元的类。


基本实验

我对JDK进行了基本的实验。我克隆了open-jdk森林,并成功构建了它。正如预期的那样,头文件生成为 和 (感谢 ) 和 (感谢他们的本机方法),但不是为 , ...IntegerLong@NativeFloatDoubleByteShort

    ls -l build/macosx-x86_64-normal-server-release/support/headers/java.base/java_lang_*
    ...
    java_lang_Double.h
    java_lang_Float.h
    java_lang_Integer.h
    java_lang_Long.h
    java_lang_Object.h
    java_lang_Package.h
    ...
    

然后我试图从字段中删除,我试图再次构建,但我得到一个错误:@NativeIntegerjdk

jdk/src/java.base/unix/native/libnio/ch/FileChannelImpl.c:35:10: fatal error: 'java_lang_Integer.h' file not found
#include "java_lang_Integer.h"
         ^
1 error generated.

从逻辑上讲,因为标头尚未生成。

我还确认了包含在几个c和cpp文件中java_lang_Integer.h

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Integer.h" {} \; -print
#include "java_lang_Integer.h"
./jdk/src/java.base/unix/native/libnio/ch/FileChannelImpl.c
#include "java_lang_Integer.h"
./jdk/src/java.base/unix/native/libnio/ch/IOUtil.c
#include "java_lang_Integer.h"
./jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
#include "java_lang_Integer.h"
./jdk/src/java.base/windows/native/libnio/ch/FileChannelImpl.c
#include <java_lang_Integer.h>
./jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp

喜欢Long

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Long.h" {} \; -print
#include "java_lang_Long.h"
./jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c

喜欢Float

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Float.h" {} \; -print
#include "java_lang_Float.h"
./jdk/src/java.base/share/native/libjava/Float.c
#include "java_lang_Float.h"
./jdk/src/java.base/share/native/libjava/ObjectInputStream.c
#include "java_lang_Float.h"
./jdk/src/java.base/share/native/libjava/ObjectOutputStream.c

和喜欢Double

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Double.h" {} \; -print
#include "java_lang_Double.h"
./jdk/src/java.base/share/native/libjava/Double.c
#include "java_lang_Double.h"
./jdk/src/java.base/share/native/libjava/ObjectInputStream.c
#include "java_lang_Double.h"
./jdk/src/java.base/share/native/libjava/ObjectOutputStream.c

但两者都不是Short

find .  \( -name "*.c" -o -name "*.cpp" \) -exec grep "java_lang_Short.h" {} \; -print

也不是 , 也不是 。ByteCharacter


结论

在所有这些类型中,只有 、 、 在 jdk 的原生源代码中使用。IntegerLongFloatDouble

只有 和 字段用 @Native 进行注释,因为它们没有本机方法(与 和 相反)IntegerLongFloatDouble)


答案 2

贡塔德做对了

javac 将(可选地)生成一个本机头文件,如果一个类包含用 @Native 注释的本机方法或字段。

这是JDK 8中javac的新功能,与Jigsaw模块系统无关,正如一些人所推测的那样。JDK 构建系统会记录 javac 何时生成了新的/不同的本机头文件,并仅在必要时才触发本机代码的重新编译。

Jonathan Gibbons,Oracle的javac团队


推荐