关于一段 Java 代码的疑问,求解答 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
seedscoder
V2EX    Java

关于一段 Java 代码的疑问,求解答

  •  
  •   seedscoder 2023-12-16 00:42:44 +08:00 2427 次点击
    这是一个创建于 667 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我有如下一段 JAVA 代码,为什么 4 次都是输出 0 ?我第一反应应该是递增输出,求大佬们解答

    public class DemoApp { private static final AtomicInteger nextIndex = new AtomicInteger(); public static final int ARIABLES_TO_REMOVE_INDEX = nextVariableIndex(); public static int nextVariableIndex() { return nextIndex.getAndIncrement(); } public static void main(String[] args) { System.out.println(VARIABLES_TO_REMOVE_INDEX); System.out.println(VARIABLES_TO_REMOVE_INDEX); System.out.println(VARIABLES_TO_REMOVE_INDEX); System.out.println(VARIABLES_TO_REMOVE_INDEX); } } 

    上面这段代码其实摘抄自 netty InternalThreadLocalMap

    public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap { private static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>(); private static final AtomicInteger nextIndex = new AtomicInteger(); // Internal use only. public static final int VARIABLES_TO_REMOVE_INDEX = nextVariableIndex(); private static final int DEFAULT_ARRAY_LIST_INITIAL_CAPACITY = 8; public static int nextVariableIndex() { int index = nextIndex.getAndIncrement(); if (index >= ARRAY_LIST_CAPACITY_MAX_SIZE || index < 0) { nextIndex.set(ARRAY_LIST_CAPACITY_MAX_SIZE); throw new IllegalStateException("too many thread-local indexed variables"); } return index; } 

    因为看到网上都说 InternalThreadLocalMap 存储元素的数组 0 号位置是一个类型为 set 的元素,所以对这段代码有点疑惑,那为什么 VARIABLES_TO_REMOVE_INDEX 不直接写 0 ?

    9 条回复    2023-12-22 15:33:27 +08:00
    geelaw
        1
    geelaw  
       2023-12-16 00:51:31 +08:00 via iPhone   1
    因为直接写 0 不会导致 nextIndex 增加到 1 ?
    revers
        2
    revers  
       2023-12-16 00:59:04 +08:00   1
    nextVariableIndex() 只在赋值的时候使用了一次,所有 VARIABLES_TO_REMOVE_INDEX 值为 0 ,但是 nextIndex 值变为了 1
    seedscoder
        3
    seedscoder  
    OP
       2023-12-16 00:59:49 +08:00
    @geelaw 我看网上大佬的源码分析文章,都是说数组 0 号位置元素的类型是 set ,看起来不需要增加 1 ;

    另外我问了一下 ChatGPT ,它的回答:


    ```

    VARIABLES_TO_REMOVE_INDEX 被定义为一个常量,其实质上是在类加载的时候通过 nextVariableIndex() 方法获取的值。在 Java 中,类加载时会执行静态代码块,这个时候 nextVariableIndex() 方法被调用,得到的结果会被赋值给 VARIABLES_TO_REMOVE_INDEX 。由于 VARIABLES_TO_REMOVE_INDEX 是一个 final 常量,它的值在类加载后就不会发生变化。

    这样设计的一个优势是,在运行时获取这个值只需要一次计算,而不必每次调用的时候都重新计算。这有助于提高性能,特别是在需要频繁访问这个索引的情况下。

    所以,尽管 nextVariableIndex() 方法被调用,但由于其结果在类加载时就确定了,并且是不可变的,因此被定义为一个常量。这样做的目的是为了提高效率,同时保证这个值在运行时是不可变的。
    ```



    那反正只运行一次,跟直接写 0 好像没多大区别?
    seedscoder
        4
    seedscoder  
    OP
       2023-12-16 01:01:37 +08:00
    @revers 好的,感谢大佬
    yumenawei
        5
    yumenawei  
       2023-12-16 07:09:33 +08:00 via Android
    @livid 很好奇三楼这种情况你怎么处理?
    xuanbg
        6
    xuanbg  
       2023-12-16 10:08:22 +08:00
    VARIABLES_TO_REMOVE_INDEX 初始化后就没被改变过
    L0L
        7
    L0L  
       2023-12-16 13:59:17 +08:00
    chatGPT:
    在你给出的 Java 代码片段中,VARIABLES_TO_REMOVE_INDEX 是一个静态常量,它在类加载时被初始化。静态常量初始化是在类首次被加载到 JVM 时完成的,且该初始化过程只会执行一次。

    java
    复制
    public static final int VARIABLES_TO_REMOVE_INDEX = nextVariableIndex();
    这行代码调用 nextVariableIndex() 方法,该方法通过 nextIndex.getAndIncrement() 获取当前的值并递增 nextIndex 。然而,VARIABLES_TO_REMOVE_INDEX 在初始化后就不会再改变,它保留了 nextVariableIndex() 方法第一次调用时的返回值,即 0 。

    当你在 main 方法中多次打印 VARIABLES_TO_REMOVE_INDEX 时,你实际上每次都在打印同一个被初始化时确定的常量值,即 0 。即使 nextIndex 的值在每次调用 nextVariableIndex() 时都会递增,VARIABLES_TO_REMOVE_INDEX 仍然保持不变,因为它是一个 final 常量。

    至于为什么 VARIABLES_TO_REMOVE_INDEX 不直接写成 0 ,而是通过调用方法来初始化,可能是因为 Netty 的设计者想要保持代码的一致性和可维护性。如果索引的生成逻辑需要变更,他们只需修改 nextVariableIndex() 方法的实现即可,而不需要去手动改动硬编码的值。此外,如果后续添加了新的索引,则可以确保 VARIABLES_TO_REMOVE_INDEX 的值是正确的,而不会与其他索引发生冲突。

    在 InternalThreadLocalMap 的实际使用上,将 VARIABLES_TO_REMOVE_INDEX 设置成一个通过递增得到的值,可能是为了确保这个索引是唯一的,并且如果 InternalThreadLocalMap 类中还有其他静态变量也通过 nextVariableIndex() 初始化,那么每个静态变量都将得到一个不同的索引值。

    最后,关于数组 0 号位置是一个类型为 set 的元素,这是 Netty 的内部实现细节,它可能是为了某种特定的优化或者内部使用的便捷性。由于 VARIABLES_TO_REMOVE_INDEX 是 public static final 的,假如它被设为了 0 ,那么它就不能代表特殊的内部状态或者其他索引了,因此可以推断 Netty 设计者有意将其设置为通过 nextVariableIndex() 方法动态生成的值。
    jaffe24
        8
    jaffe24  
       2023-12-16 23:55:37 +08:00
    这主要涉及到类加载机制
    dongisking
        9
    dongisking  
       2023-12-22 15:33:27 +08:00
    ```
    package ClassLoader;

    import java.util.concurrent.atomic.AtomicInteger;

    public class InternalThreadLocalMap {
    private static final AtomicInteger nextIndex = new AtomicInteger();

    public static final int VARIABLES_TO_REMOVE_INDEX = nextVariableIndex();

    public static int nextVariableIndex() {
    System.out.println("test");
    return nextIndex.getAndIncrement();
    }

    public static void main(String[] args) {
    System.out.println("33");
    System.out.println(VARIABLES_TO_REMOVE_INDEX);
    System.out.println(VARIABLES_TO_REMOVE_INDEX);
    System.out.println(VARIABLES_TO_REMOVE_INDEX);
    System.out.println(VARIABLES_TO_REMOVE_INDEX);
    }
    }

    ```
    输出
    test
    33
    0
    0
    0
    0
    VARIABLES_TO_REMOVE_INDEX 在类加载的时候已经初始化了,后面没有发生过变化了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1474 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 16:41 PVG 00:41 LAX 09:41 JFK 12:41
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86