StringBuilder 实现 Comparable 但不覆盖 equals

问题描述

我不明白这个 line from javadoc(在“API 注释”副标题下):

StringBuilder 实现了 Comparable 但不覆盖 equals。因此,StringBuilder 的自然顺序与 equals 不一致。

我是 Java 初学者,您能简单解释一下吗?

解决方法

这意味着 StringBuilder.compareTo()StringBuilder.equals() 并不总是一致。

var sb1 = new StringBuilder("foo");
var sb2 = new StringBuilder("foo");
assert sb1.compareTo(sb2) == 0;      // as you would expect.
assert sb1.equals(sb2) == true;      // surprise - it fails

现在有点混乱:

var map = new HashMap<StringBuilder,String>();
map.put(sb1,"lorem ipsum");
assert map.size() == 1;
map.put(sb2,"dolor sit amet");
assert map.size() == 1;            // fails - it's 2

var set = new TreeSet<StringBuilder>();
set.add(sb1);
assert set.size() == 1;
set.add(sb2);
assert set.size() == 2;           // you'd think this should be 2 but it fails! 

那是因为 HashMap 适用于 equals()SortedSet 适用于 compareTo()


注意 1:在 equals()

StringBuilder 扩展 Object,表示继承 Object.equals();但它不会覆盖 equals(),这意味着 StringBuilder.equals() 实际上是 Object.equals()

Object.equals() 基本上是 ==,即当且仅当两个对象的内存地址相同时它才返回 true。

Object.equals() java doc


注意 2:为什么?

仅从 JDK11 开始,StringBuilder 实现了 Comparableequals() 中的任何伴随变化都可能导致一些旧的客户端代码中断;所以,我认为,遵循 Java 保持向后兼容的传统,他们放弃了这个想法。