0

在第 5.1.4 章,Java 中的现代编译器实现

public class Symbol {
  private String name;
  private Symbol (String n) { name = n; }
  private static java.util.Dictionary dict = new java.util.Hashtable();

  public String toString() { return name; }

  public static Symbol symbol(String n) {
    String u = n.intern();
    Symbol s = (Symbol)dict.get(u);
    if (s == null) { s = new Symbol(u); dict.put(u, s); }
    return s;
  }
}

我不明白为什么在这里使用字符串实习生,因为Hashtable用于key.equals(...)检查身份。

你能告诉我原因吗?谢谢!

4

2 回答 2

1

我希望你知道做什么String#intern。简单地说,如果给定字符串已经不是它的一部分,或者如果字符串已经是字符串池的一部分,它将返回给定的字符串到由 String 类维护的字符串池中,则返回该对象。因此,字符串池中只会有 String 的这个特定值的副本。

这意味着当我们这样做时aString.intern(),它总是放在 Map 中,下次从 map 中获取时,equals 将在比较本身anotherString.intern()中返回 true 。==这将避免遍历整个字符串来验证相等性。如果存储在地图中的字符串可能很大并且如果地图将被频繁地搜索(获取或包含操作),这可以证明是一个很大的性能改进。

于 2016-03-30T11:46:26.330 回答
1

在编程中有很多“智慧”、“谣言”、“魔法”或“迷信”。

正如@RealSkepic 指出的那样,在Java 7u4 之前, String.substring 将使用原始字符串的一部分而不是复制该部分。虽然这在许多情况下提高了性能,但它可能导致内存泄漏。使用intern()是避免这种情况的一种方法,尽管它可能会产生自己的内存清理问题,这并不理想。使用new String(oldString)是另一种方法,但您现在不需要这样做。

人们经常出于“性能原因”尝试某些东西,但不知道如何测试它,或者只是不检查它是否真的有帮助。我不时这样做,即使我知道要避免它,因为它经常不正确,或者只是使代码混乱。

很可能是作者发现了一种情况,或者听说有人通过使用节省了很多内存String.intern(),在特定情况下,它可以做到这一点,但它不像仙尘一样,你撒上一点性能魔法,一切都会变得更好。大多数优化代码的晦涩技巧仅适用于非常特定的用例。

一个类似的例子是人们在多线程中使用锁或线程安全集合。在周围撒上足够多的这种东西,程序似乎可以停止错误,但您并没有真正解决问题,只是在某些偶然发生的变化并且您的错误再次出现时更难找到。

于 2016-03-30T08:02:12.137 回答