【问题标题】:Is String str = new String("my string") really less efficient?String str = new String("my string") 真的效率低吗?
【发布时间】:2018-01-04 20:42:37
【问题描述】:

我经常看到有人说String str = new String("my string") 比写String str = "my string", 效率低,因为前者创建了一个静态“my string” 对象,然后new 是一个从静态对象复制而来的String 对象.

但是,鉴于这里的语言是如此简单和明确,我很难想象 Java 优化器不会花任何精力将前者简单地转换为后者。为什么它真的会选择更费力的方式呢?如果 Java 确实对其进行了优化,会有什么负面影响?

【问题讨论】:

  • 将实习字符串描述为“静态”实际上并不准确,因为它们不属于任何给定的类。无论如何,对象不是“静态的”或“实例级的”,只有对它们的引用才是。
  • 确实简单明了:根据语言规范,调用构造函数must create a new object。您提议的优化将违反该规则。

标签: java string optimization


【解决方案1】:

但是,鉴于这里的语言是如此简单和明确,我很难想象 Java 优化器不会花任何精力将前者简单地转换为后者。

首先,你不应该仅仅因为你认为编译器会用更快的东西代替它而写下说做一些慢的代码。

其次,编译器一般无法对此进行优化,因为new 保证了新对象的创建。如果你这样做了

String str = new String("my string");

那么保证str != "my string"。 Java 只能优化出new,前提是它可以证明String 对象的身份对程序的执行无关紧要。

【解决方案2】:

查看为String s1 = "1": 生成的字节码

LDC "1"
ASTORE 1

对于String s2 = new String("2"):

NEW java/lang/String
DUP
LDC "2"
INVOKESPECIAL java/lang/String.<init> (Ljava/lang/String;)V
ASTORE 2

后一个例子是多余的,更复杂。在这种情况下,编译器不会进行任何优化。 保证将创建一个 String 类的新实例。

使用String str = "my string",JVM 可以重用 String 的实例,而不是创建一个新实例。考虑下一个例子:

String s1 = "1";
String s2 = "1";
System.out.println(s1 == s2); // true  => same reference, s1 & s2 point to the same object

String s3 = "1";
String s4 = new String("1");
System.out.println(s3 == s4); // false => s3 & s4 point to different objects

【讨论】:

  • 这并不能回答为什么不能优化的问题。
【解决方案3】:

您应该始终尽可能编写最简单、最清晰的代码。在 90+% 的时间里,开发人员的效率比处理器效率更重要。因此,即使 JIT 可以优化它,但它没有,你给开发人员带来了负担。为什么这段代码比它需要的更复杂?最难找到的答案是;完全没有理由。

为什么它真的会选择更费力的方式呢?

当人们从 C++ 等其他语言迁移时,他们会随身携带他们的习语。例如,在 C++ 中,您需要编写 new string("some text"),但在 Java 中这是不必要的冗余。

如果 Java 确实对其进行了优化,会有什么负面影响?

Java 可以通过逃逸分析对其进行优化。如果字符串在内联后没有转义当前方法,则new String 可以放在堆栈上,因此因为它是多余的而被消除。但那是无关紧要的。对于必须维护代码的任何人来说,您已经让他们的生活变得更加艰难,而 JIT 不会帮助您。

【讨论】:

    【解决方案4】:

    这不是性能问题。它只是以一种不必要的复杂方式做某事。除非您正在使用实习生 Strings== 进行比较,否则代码也将以相同的方式工作。

    Java 不会优化任何东西,因为没有什么可以优化的。如果你使用 String 字面量,相同的字面量会减少到字符串池中的同一个实例,所以

    String foo = "foo";
    String bar = "foo";
    System.out.println(foo == bar); // True, the same object
    

    但是使用显式构造函数

    String foo = "foo";
    String bar = new String("foo");
    System.out.println(foo == bar); // False, bar is explicitly created as a new object with the constructor
    

    但是,由于您仍应使用 equals() 进行所有对象比较,因此在运行代码时不会发现任何差异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-19
      • 2020-11-13
      • 2011-04-21
      • 2011-04-07
      • 2013-03-27
      • 1970-01-01
      • 2011-09-06
      相关资源
      最近更新 更多