【问题标题】:What are the benefits of using identical String literals instead of a final variable?使用相同的字符串文字而不是最终变量有什么好处?
【发布时间】:2011-01-28 16:09:43
【问题描述】:

我遇到了一个包含多个使用字符串文字“foo”的类。

我想知道的是,使用这种方法而不是将 String 声明为 final 并用 final 变量替换所有文字有什么好处和影响(在对象创建、内存使用和速度方面) ?

例如(虽然显然不是真正的单词用法):

private static final String FINAL_STRING = "foo";

public void stringPrinter(){
    for(int i=0;i<10;i++){
        System.out.println(FINAL_STRING);
    }
}

对比:

public void stringPrinter(){
    for(int i=0;i<10;i++){
        System.out.println("foo");
    }
}

哪个更可取,为什么(假设字符串值保持不变)?

上面的(第二个)示例会导致创建 10 个 String 对象,还是 JVM 会意识到实际上只使用了一个文字,并创建一个引用。如果是这样,将 String 声明为 final 有什么好处(如第一个示例中所示)?

如果解释的代码确实用单个引用替换了字符串文字,那么如果相同的文字出现在多个地方,这是否仍然适用:

public void stringPrinter(){
    for(int i=0;i<5;i++){
        System.out.println("foo"); // first occurence
        System.out.println("foo"); // second occurence
    }
}

【问题讨论】:

  • 我不会假设以前的开发人员选择重复文字而不是使用常量,这看起来像是懒惰。
  • 奇怪的是,他们实际上声明了常量但没有使用它。因此,为什么我对可能的原因感兴趣。但同意,我认为这只是懒惰。

标签: java string final


【解决方案1】:

它们将完全相同。在这两种情况下,文字都被保留(导致该字符串与所有其他常量/文字共享相同实例的任何编译时常量表达式),并且智能编译器+运行时应该可以轻松地将两者都减少到最优化的示例。

优势更多在于可维护性。如果你想改变文字,你只需要用一个常量改变一次出现,但如果它们被内联包含,你需要搜索和更改每个实例。

【讨论】:

    【解决方案2】:

    From the JLS
    String 类型的编译时常量始终是“内部的”,以便使用 String.intern 方法共享唯一的实例。

    所以,不,只有一个字符串对象。

    正如 Mark 所说,这完全是可维护性的问题,而不是性能问题。

    【讨论】:

      【解决方案3】:

      优势不在于性能,而在于可维护性和可靠性。

      让我举一个我最近遇到的真实例子。程序员创建了一个函数,该函数采用一个字符串参数来标识事务的类型。然后在程序中他做了字符串与这种类型的比较。喜欢:

      if (type.equals("stock"))
      { ... do whatever ... }
      

      然后他调用了这个函数,将值“Stock”传递给它。

      你注意到大小写的不同了吗?原来的程序员也没有。事实证明,这是一个相当微妙的错误,因为即使查看两个列表,我也没有发现大小写的差异。

      如果他声明了一个最终的静态,比如说

      final static String stock="stock";
      

      那么当他第一次尝试传入“Stock”而不是“stock”时,他会得到一个编译时错误。

      在这个例子中更好的是创建一个枚举,但我们假设他实际上必须将字符串写入输出文件或其他东西,所以它必须是一个字符串。

      使用 final statics 至少有 x 个优势:

      (1) 如果你拼错了,你会得到一个编译时错误,而不是一个可能很微妙的运行时错误。

      (2) 静态变量可以为一个值分配一个有意义的名称。哪个更容易理解:

      if (employeeType.equals("R")) ...
      

      if (employeeType.equals(EmployeeType.RETIRED)) ...
      

      (3) 当有多个相关值时,可以将一组final statics放在程序的顶部,从而告知未来的读者所有可能的值是什么。当我看到一个函数将一个值与两个或三个文字进行比较时,我已经有很多次了。这让我想知道:是否还有其他可能的值,或者就是这样? (通常最好有一个枚举,但那是另一回事了。)

      【讨论】:

        【解决方案4】:

        所有字符串字面量都保存在字符串缓存中(这是跨所有类)

        使用常量可以使代码更清晰,给字符串一些上下文,并使代码更容易维护,尤其是如果相同的字符串出现在多个地方。

        【讨论】:

          【解决方案5】:

          这些字符串文字是内部化的,因此不会在循环中创建新的 String 对象。但是,两次使用相同的文字仍然可能是代码异味的标志;但不是在速度或内存使用方面。

          【讨论】:

            【解决方案6】:

            在您提供的情况下,我认为在某处将其声明为 FINAL_STRING 的最大原因是确保它位于一个集中位置。该字符串常量只会有一个实例,但第一个示例更容易维护。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-04-03
              • 1970-01-01
              相关资源
              最近更新 更多