在第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(...)
来检查身份。
答案 0 :(得分:1)
在编程方面,有很多"智慧","谣言","魔术"或者"迷信"到处走走。
正如@RealSkepic所指出的,在Java 7u4之前,String.substring将使用原始字符串的一部分而不是复制该部分。虽然这在许多情况下改善了性能,但它可能导致内存泄漏。使用intern()
是避免这种情况的一种方法,尽管它可以创建它自己的内存清理问题,这是不理想的。使用new String(oldString)
是另一种方法,但您现在不应该这样做。
人们经常会因为性能原因而尝试事情。但不知道如何测试它,或者只是不检查它实际上有帮助。我不时这样做,即使我知道要避免它,因为它经常是不正确的,或者只是让代码混乱。
作者很可能发现了一种情况,或者听说有人使用String.intern()
节省了大量内存,在特定情况下,它可以做到这一点,但它不像你撒上的仙尘一点性能魔术,一切都更好。大多数这些用于优化代码的模糊技巧仅适用于非常特定的用例。
类似的例子是人们在多线程中使用锁或线程安全集合。充分利用这一点并且程序似乎可以阻止错误,但是您还没有真正解决问题,只是在发生偶然更改并且您的错误再次出现时更难找到。
答案 1 :(得分:1)
我希望你知道String#intern
的作用。简单地说,它将把给定字符串添加到由String类维护的字符串池中(如果它已经不是它的一部分),或者如果该字符串已经是String池的一部分,则返回该对象。因此,字符串池中只有String的特定值的副本。
这意味着当我们执行aString.intern()
时,这总是放在地图中,下次从地图获取anotherString.intern()
时,等于将在{{1}中返回true比较本身。这将避免遍历整个字符串以验证相等性。如果存储在地图中的字符串可能很大并且要经常搜索(获取或包含操作)Map,那么这可以证明是一个很好的性能改进。