TLDR:跳到结论
为什么 SIZE 常量只有 @Native 用于 Integer 和 Long?
@Native的简史
我在邮件列表上进行了一些搜索。我发现了一些有趣的东西。
一开始注解(12)javax.tools.annotation.ForceNativeHeader
被介绍到
在类上触发 javah。
它被com.sun.tools.javac.processing.NativeapiVisitor使用。通过查看代码我们可以看到,如果类声明了一些原生方法或者类被注解@ForceNativeHeader,就会生成原生头。
后来这个注解被重命名为GenerateNativeHeader(12)。
那么 this annotation was added to several types(尤其是Integer 和Long)加上一个有趣的评论:
/* No native methods here, but the constants are needed in the supporting JNI code */
@GenerateNativeHeader
public final class Long extends Number implements Comparable<Long> {...
但是通过添加这个注解它会将a problematic dependency从基础模块添加到包含javax.tools的模块中。因此注释从Integer 和Long 中删除,这些文件明确为added to the build process,因为不再自动生成标头..."(hopefully temporary) hack"。
所以一个新的注释java.lang.annotation.Native was created 并用于Integer 和Long。注释被设置为TargetType FIELD。
注释应该直接应用于需要导出的常量字段——而不是整个类。
这些东西的全部目的是:
javac 可以为包含本地方法的类生成本地头文件。
Integer和Long就是这样
这是JEP 139: Enhance javac to Improve Build Speed的一部分:
javah 将在任何包含本地方法的类上自动运行,并且生成的 C-headers 将放在 (-h) headerdir 中。一个新的注解 @ForceNativeHeader 用于具有需要导出到 JNI 的最终静态原语但没有本机方法的类。
基本实验
我在 JDK 上做了一个基本的实验。我克隆了 open-jdk 森林,并成功构建了它。正如预期的那样,为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,并尝试再次构建jdk,但出现错误:
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。
结论
在所有这些类型中,只有Integer、Long、Float、Double在jdk的本机源代码中使用。
并且只有 Integer 和 Long 字段用 @Native 注释,因为它们没有本地方法(与 Float 和 @987654384 相对) @)