为什么SIZE常量只有@Native整数和长?
我了解@Native
注释的@Native
。
表示定义一个常数值的字段可以从本地代码引用。 注释可以被用作生成本地头文件以确定是否需要头文件的工具的提示,并且如果是的话,它应该包含什么声明。
然而,在阅读java源代码时,我注意到在类Integer
和Long
, SIZE
常量是@Native
而不是Float,Byte,Double,Short和Character。
请注意,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_VALUE
和MIN_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整数和长?
TLDR :跳转到结论
为什么SIZE常量只有@Native整数和长?
@Native
我在邮件列表上进行了一些search。 我发现了一些有趣的事情。
首先引入一个注释( 1 2 ) javax.tools.annotation.ForceNativeHeader
在类上触发javah。
它由com.sun.tools.javac.processing.NativeapiVisitor
。 通过查看代码,我们可以看到,如果类声明了一些本地方法,或者该类是注解@ForceNativeHeader
则会生成本地头。
稍后,这个注解被重命名为GenerateNativeHeader
( 1 2 )。
然后, 这个注释被添加到几个types (特别是整数和长 )与一个interresting评论:
/* 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的模块中。 所以从Integer
和Long
中删除了这个注释,并且这些文件被明确地添加到构build过程中,因为头部不再被自动生成…… “(希望暂时的)破解” 。
所以 创build了一个新的批注java.lang.annotation.Native
,并在Integer和Long中使用 。 注解被设置为TargetType FIELD
。
注释应直接应用于需要导出的常量字段 – 而不是整个类。
所有这些东西的目的是:
javac可以为包含本机方法的类生成本地头文件。
Integer
和Long
就是这种情况
这是JEP 139的一部分:增强javac提高生成速度 :
javah将自动运行在任何包含本地方法的类上,生成的C头文件将放入(-h)headerdir中。 新的批注@ForceNativeHeader用于具有最终静态基元的类,这些基元需要导出到JNI,但没有本地方法。
一个基本的实验
我在JDK上做了一个基本的实验。 我克隆开放jdk森林,我成功地build立它。 正如所料,为Integer
和Long
生成的头文件(感谢@Native
)和Float
和Double
(感谢他们的本地方法),但不是Byte
, Short
…
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 ...
然后我试图从Integer
字段中删除@Native
,我试图再次构buildjdk
但我得到一个错误:
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.
因为头还没有被生成。
我也确认了java_lang_Integer.h
包含在几个c和cpp文件中 :
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
也不是Byte
,也不是Character
。
结论
在所有这些types中, 只有 Integer
, Long
, Float
, Double
被用在jdk的本地源代码中 。
只有Integer
和Long
字段用@Native
标注,因为它们没有本地方法 (与Float
和Double
相反)
gontard是对的 。
如果一个类包含用@Native注解的本地方法或字段,javac将(可选)生成一个本地头文件。
这是JDK 8中的一个新function,与Jigsaw模块系统无关,正如一些人猜测的那样。 当javac生成新的/不同的本地头文件时,JDK构build系统会注意到,并且在必要时使用它来触发重新编译本机代码。
Oracle的javac团队Jonathan Gibbons
看看这个问题,并解决它,看起来像这样做已经完成了解决处理一个特殊类的拼图的头文件生成
拼图是指定用于Java SE平台和JDK的模块系统。 更多细节在这里
这是一个相应的变更集 。 你可以看到一个评论,
对拼图基本模块中类的头文件生成的特殊处理,目前无法添加注释GenerateNativeHeaders。 对于这些特定的类,java文件和类具有相同的名称,可以使依赖关系变得简捷。
从变更集我看到,除了java.lang.Integer
和java.lang.Long
,还有一些在java.net.SocketOptions
, sun.nio.ch.IOStatus
, java.io.FileSystem
属性被改为@Native
。
所以我认为只有那些需要解决拼图的依赖。