Java TreeSet为何允许重复元素?Comparator去重机制失效求助
嘿,刚接触Java和StackOverflow的话遇到这种问题太正常了,别慌!咱们来一步步搞清楚TreeSet为啥会让你觉得它允许重复元素~
首先得明确TreeSet判断「重复」的核心规则:当你给TreeSet传入自定义Comparator时,它完全依赖这个Comparator的返回值来判断元素是否相等——只有当comparator.compare(a, b) == 0时,TreeSet才会认为a和b是重复元素,从而拒绝添加后者。
那你的TreeSet出现「重复」的情况,大概率是下面两个原因之一:
1. 你的Comparator逻辑没正确识别相等的Song对象
你用了c1.toString().compareTo(c2.toString())作为比较逻辑,这意味着:
- 只有当两个Song对象的
toString()返回完全相同的字符串时,TreeSet才会判定它们重复。 - 如果你认为是「重复」的两个Song对象,它们的
toString()返回的字符串不一样,TreeSet就会把它们当成不同元素添加进去。
举个例子:假设你的Song类有title和artist属性,但toString()只输出了title,那两首同名但不同歌手的歌会被TreeSet视为不同元素;反过来,如果你的toString()输出了所有关键属性,但你误创建了两个属性完全相同的Song对象,TreeSet会正确拒绝重复。
2. Song类可能没正确重写toString()方法
如果你的Song类没有重写Object类的toString(),默认的toString()会输出对象的内存地址(比如Song@123456)。这意味着即使两个Song对象的属性完全一样,它们的toString()结果也会不同,TreeSet自然会把它们当成不同元素添加。
怎么修复?
根据你的需求,有两种实用的解决方案:
方案一:修正Comparator的比较逻辑(更推荐)
如果你希望根据Song的核心属性(比如title+artist)来判断重复,直接比较这些属性而不是依赖toString():
Comparator<Song> comp = (Song c1, Song c2) -> { // 先比较歌名,再比较歌手,确保唯一性 int titleCompare = c1.getTitle().compareTo(c2.getTitle()); if (titleCompare != 0) { return titleCompare; } return c1.getArtist().compareTo(c2.getArtist()); }; songs = new TreeSet<>(comp);
方案二:正确重写Song类的toString()(如果坚持用toString比较)
确保toString()返回的字符串能唯一标识一个Song对象,比如包含所有关键属性:
public class Song { private String title; private String artist; // 构造器、getter、setter省略 @Override public String toString() { return "Song{" + "title='" + title + '\'' + ", artist='" + artist + '\'' + '}'; } }
最后提个小提醒:TreeSet是有序集合,它的排序完全由你提供的Comparator决定,所以如果你的比较逻辑既要判断重复,又要控制排序顺序,一定要把逻辑写得清晰明确哦~
内容的提问来源于stack exchange,提问作者M. P.

