【问题标题】:Do final members assigned constants on declaration get optimized at run-time to 'static final's?在声明中分配常量的最终成员是否在运行时优化为“静态最终”?
【发布时间】:2009-08-06 15:19:47
【问题描述】:

当我在 Java 代码中定义常量值时,我通常将它们声明为“private static final”,但最近我一直在维护将常量定义为“private final”的代码。

我目前正在优化,想知道是否要“静态化”这些。

例如

public class X {
    private final String SOME_CONST = "Whatever";
}

上面的代码(在运行时)是否等同于下面的代码,所以只保存了 1 个 'SOME_CONST' 的副本?

public class X {
    private static final String SOME_CONST = "Whatever";
}

我以为这是相当基本的,但我在任何地方都找不到答案。

[编辑] 有些人已经回答了正在实习的 String 实例。抱歉,我应该选择一个更好的例子,在我正在查看的情况下,它不仅仅是字符串,而是许多不同的类型(一些标准,一些用户定义)。

我对“私人决赛”与“私人静态决赛”声明的效果更感兴趣。

【问题讨论】:

    标签: java optimization


    【解决方案1】:

    SOME_CONST被声明为非静态时,虚拟机将创建一个String实例,其内容为"Whatever"。但是,X 类的所有实例都将包含对此String 对象的引用。因此,您的String 只有一个实例,但对它的引用却很多。

    可能值得将该字段设为静态以避免不必要的引用。

    【讨论】:

      【解决方案2】:

      不。在这两种情况下,只有一个 String 实例是 "Whatever",因为所有 String 文字都被保留。

      当字段为static 时,则从X.class 对象中只有一个对String 实例的引用。但是,在非static 字段的情况下,每个对象将包含对String 实例的不同引用。

      换句话说,将字段设为非static 会导致每个对象的 constance 引用开销(~ 32 位或 64 位)。

      【讨论】:

      • 但是如果我们有这个呢? private final String SOME_CONST = new String("Whatever");在这种情况下,String 不是实习的,每个类将指向不同的 String。
      • @pjp,当使用初始化器时,非静态字段时会有多个实例。在静态字段的情况下,只会初始化一个实例。
      【解决方案3】:

      final 设为static final 有一个注意事项,即如果有一种方法可以构建变量。如果具有动态集的变量实例不止一个,则变量的值会卡住。出于性能原因,很多时候决赛都是动态创建的;这很危险,因为有人可能决定优化代码并static 他们。

      在您的示例中没有问题,但是如果您将有多个设置变量的类或方法实例并且动态设置,请确保最终没有静态修饰符。除非在设置 var 的地方存在大循环,否则破坏代码的危险不值得非常小的性能增益。

      【讨论】:

      • 不,问题的关键是成员在声明时设置为常量值,而不是动态设置
      【解决方案4】:

      FindBugs 有用地指出这样的 final 成员应该是静态的。可以由此推断优化没有发生。

      【讨论】:

      • 我就是这么想的。谢谢
      【解决方案5】:

      final 字符串在编译时内联使用。所以如果你写

      final String a="A";
      void foo(){ System.out.println(a):}
      

      编译器写

      final String a="A";
      void foo(){ System.out.println("A"):}
      

      但是据我所知,编译器不会将其写为静态的 - 您仍然会在每个实例中声明引用。

      【讨论】:

        【解决方案6】:

        如果你有

        public class X {
            private final SomeClass FIELD = new SomeClass();
        }
        

        编译器无法对此进行优化,并且每次创建 X 的新实例时都必须创建 SomeClass 的新实例。如何知道 SomeClass 构造函数没有从某个流中读取某些内容或打开某个 DB 连接?在这种情况下,优化为静态会破坏代码。

        编辑

        改变

        final SomeClass FIELD = new SomeClass();
        

        static final SomeClass FIELD = new SomeClass();
        

        是从 X 的每个实例都有自己的 SomeClass 实例的情况到 X 的所有实例共享同一个 SomeClass 实例的情况的变化。除了效率之外,它可能不会改变任何东西,或者它可能会破坏所有代码(想象每个实例共享一个 JDBC 连接,而不是每个类实例一个连接)。这取决于 SomeClass 的实现以及它的用途。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-11-14
          • 1970-01-01
          • 2015-08-02
          • 1970-01-01
          • 2016-01-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多