【问题标题】:Why is the SIZE constant only @Native for Integer and Long?为什么 SIZE 常量仅适用于 Integer 和 Long 的 @Native?
【发布时间】:2015-04-30 12:06:40
【问题描述】:

我了解@Native注解的使用。

表示可以引用定义常量值的字段 来自本机代码。注释可以被工具用作提示 生成原生头文件,判断一个头文件是否为 需要,如果需要,它应该包含哪些声明。

但是,在阅读 java 源代码时,我注意到在 IntegerLong 类中,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_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 for Integer 和 Long ?

【问题讨论】:

    标签: java java-8


    【解决方案1】:

    查看问题并进行修复,看起来这是为了解决 jigsaw 中特殊类的头文件生成处理问题

    Jigsaw 是一个指定用于 Java SE 平台和 JDK 的模块系统。更多详情here

    这是一个对应的changeset。你可以看到评论,

    jigsaw 中类的头文件生成的特殊处理 当前无法添加注释的基本模块 生成NativeHeaders。对于这些特定的类,java 文件和 该类具有相同的名称,从而可以快捷方式 依赖关系。

    从变更集中我看到,为了达到目的,除了java.lang.Integerjava.lang.Long 之外,java.net.SocketOptionssun.nio.ch.IOStatusjava.io.FileSystem 中的一些属性也已更改为@Native

    所以我假设只需要那些来解决拼图的依赖关系。

    【讨论】:

    • 特殊处理已删除并替换为@Native。这并不能解释为什么只有 Integer 和 Long(而不是其他原始包装器)被注释(注意特殊处理也排除了其他包装器)。不过,检查hg blame 是个好主意。
    • 我假设 jigsaw 只需要这些类,所以这就是为什么其他类都没有改变。
    • 这并不能解释为什么只有 Long 和 Integer 的大小是原生的,这只是证实了我所看到的。而且我也不认为因为它是在拼图上完成的,所以它是专门为拼图完成的。回答“它是在 JDK 上完成以解决依赖问题”是解释为什么它在 Jigsaw 中完成的一个很好的答案吗?
    • 特殊处理和将@Native 移动到 java.lang.annotation 是为 Jigsaw 设计的,但我敢打赌,这些字段(无论是否自动生成)的使用早于它。
    • 你是说由于 JDK 模块化项目,Java 需要以某种方式使 LongInteger 以位为单位对本地 JVM 实现可见吗?我简直不敢相信这是原因......
    【解决方案2】:

    TLDR:跳到结论


    为什么 SIZE 常量只有 @Native 用于 Integer 和 Long?

    @Native的简史

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

    一开始注解(12)javax.tools.annotation.ForceNativeHeader 被介绍到

    在类上触发 javah。

    它被com.sun.tools.javac.processing.NativeapiVisitor使用。通过查看代码我们可以看到,如果类声明了一些原生方法或者类被注解@ForceNativeHeader,就会生成原生头。

    后来这个注解被重命名为GenerateNativeHeader12)。

    那么 this annotation was added to several types(尤其是IntegerLong)加上一个有趣的评论:

    /* 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的模块中。因此注释从IntegerLong 中删除,这些文件明确为added to the build process,因为不再自动生成标头..."(hopefully temporary) hack"

    所以一个新的注释java.lang.annotation.Native was created 并用于IntegerLong。注释被设置为TargetType FIELD

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


    这些东西的全部目的是:

    javac 可以为包含本地方法的类生成本地头文件。

    IntegerLong就是这样

    这是JEP 139: Enhance javac to Improve Build Speed的一部分:

    javah 将在任何包含本地方法的类上自动运行,并且生成的 C-headers 将放在 (-h) headerdir 中。一个新的注解 @ForceNativeHeader 用于具有需要导出到 JNI 的最终静态原语但没有本机方法的类。


    基本实验

    我在 JDK 上做了一个基本的实验。我克隆了 open-jdk 森林,并成功构建了它。正如预期的那样,为IntegerLong(感谢@Native)和FloatDouble(感谢他们的本地方法)生成的头文件,但不是ByteShort。 .

        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


    结论

    在所有这些类型中,只有IntegerLongFloatDoublejdk的本机源代码中使用。

    并且只有 IntegerLong 字段用 @Native 注释,因为它们没有本地方法(与 Float 和 @987654384 相对) @)

    【讨论】:

      【解决方案3】:

      gontard got it right.

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

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

      乔纳森·吉本斯, Oracle 的 javac 团队

      【讨论】:

        猜你喜欢
        • 2015-07-20
        • 1970-01-01
        • 2011-08-17
        • 1970-01-01
        • 2018-04-09
        • 2020-02-10
        • 2011-11-18
        • 2016-01-23
        • 2012-08-05
        相关资源
        最近更新 更多