我记得看到一些字符串密集型程序,它们进行大量字符串比较但相对较少的字符串操作,并且使用单独的表将字符串映射到标识符以实现高效相等和减少内存占用,例如:
public class Name {
public static Map<String, Name> names = new SomeMap<String, Name>();
public static Name from(String s) {
Name n = names.get(s);
if (n == null) {
n = new Name(s);
names.put(s, n);
}
return n;
}
private final String str;
private Name(String str) { this.str = str; }
@Override public String toString() { return str; }
// equals() and hashCode() are not overridden!
}
我很确定这些程序之一是来自 OpenJDK 的 javac,所以不是一些玩具应用程序。当然,实际的类更复杂(而且我认为它实现了 CharSequence),但你明白了 - 整个程序Name
在你期望的任何位置都乱七八糟String
,并且在需要字符串操作的极少数情况下,它转换了到字符串,然后再次缓存它们,概念上像:
Name newName = Name.from(name.toString().substring(5));
我想我理解这一点 - 特别是当周围有很多相同的字符串和很多比较时 - 但不能通过使用常规字符串和intern
ing 来实现相同的效果吗?的文档String.intern()
明确说:
...
当调用 intern 方法时,如果池中已经包含一个等于由 equals(Object) 方法确定的此 String 对象的字符串,则返回池中的字符串。否则,将此 String 对象添加到池中并返回对该 String 对象的引用。由此可见,对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 才为真。
...
那么,手动管理类类与使用类的优缺点是Name
intern()
什么?
到目前为止我想到的是:
- 手动管理地图意味着使用常规堆,
intern()
使用 permgen。 - 手动管理地图时,您喜欢类型检查,可以验证某事是 a
Name
,而一个实习字符串和一个非实习字符串共享相同的类型,因此在某些地方可能会忘记实习。 - 依赖
intern()
意味着重用现有的、优化的、久经考验的机制,而无需编写任何额外的类。 - 手动管理地图会导致代码对新用户更加困惑,并且 strign 操作变得更加繁琐。
......但我觉得我在这里错过了其他东西。