HashSet删除重复项但TreeSet没有?

blu*_*sky 5 java hashset treeset

下面的类输出是:大小是3大小是1

但是,如果我将TreeSet更改为HashSet,那么:

Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
Run Code Online (Sandbox Code Playgroud)

Set<SuggestionDetailBean> set = new HashSet<SuggestionDetailBean>();
Run Code Online (Sandbox Code Playgroud)

输出是:大小是3大小是2

使用HashSet或TreeSet大喊不改变Set的大小?使用HashSet似乎表现得像预期的那样,因为它正在删除重复项,但是当我使用TreeSet时,重复项仍然存在?我认为SuggestionDetailBean中的hashcode和equals方法是否被正确覆盖?

这是代码:

public class TestSet {

    public static void main(String args[]){

        SuggestionDetailBean s = new SuggestionDetailBean();
        s.setTagList("teddst");
        s.setUrl("testurl");

        SuggestionDetailBean s2 = new SuggestionDetailBean();
        s2.setTagList("teddst");
        s2.setUrl("testurl");

        SuggestionDetailBean s3 = new SuggestionDetailBean();
        s3.setTagList("tessdafat");
        s3.setUrl("fdfaasdfredtestur ldd");

        List<SuggestionDetailBean> list = new ArrayList<SuggestionDetailBean>();
        list.add(s);
        list.add(s2);
        list.add(s3);

        Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();
        set.addAll(list);

        System.out.println("size is "+list.size());
        System.out.println("size is "+set.size());

    }

}

public class SuggestionDetailBean implements Comparable<Object> {

    private String url;
    private String tagList;
    private String numberOfRecommendations;
    private String date;
    private String time;
    private String summary;
    private String truncatedUrl;


    public void setTruncatedUrl(String truncatedUrl) {

        if(truncatedUrl.length() > 20){
            truncatedUrl = truncatedUrl.substring(0, 20)+"...";
        }

        this.truncatedUrl = truncatedUrl;
    }

    public String getSummary() {
        if(summary == null){
            return "";
        }
        else {
            return summary;
        }
    }

    public void setSummary(String summary) {
        this.summary = summary;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }


        public String getTime() {
            return time;
        }

        public String getTruncatedUrl() {
            return this.truncatedUrl;
        }

        public void setTime(String time) {
            this.time = time;
        }

        public String getTagList() {
            if(tagList == null){
                return "";
            }
            else {
                return tagList;
            }
        }

        public void setTagList(String tagList) {
            this.tagList = tagList;
        }


        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getNumberOfRecommendations() {
            return numberOfRecommendations;
        }

        public void setNumberOfRecommendations(String numberOfRecommendations) {
            this.numberOfRecommendations = numberOfRecommendations;
        }

        @Override
        public int compareTo(Object o) {

            DateFormat formatter;
            Date date1 = null;
            Date date2 = null;  
            SuggestionDetailBean other = (SuggestionDetailBean) o;

            if(this.date == null || other.date == null){
                return 0;
            }   
            formatter = new SimpleDateFormat(SimpleDateFormatEnum.DATE.getSdfType()+" "+SimpleDateFormatEnum.TIME.getSdfType());
            try {
                date1 = (Date) formatter.parse(this.date + " " + this.time);
                date2 = (Date) formatter.parse(other.date + " " + other.time);
            } catch (ParseException e) {
                System.out.println("Exception thrown in"+this.getClass().getName()+", compareTo method");
                e.printStackTrace();
            }
            catch(NullPointerException npe){
                System.out.println("Exception thrown "+npe.getMessage()+" date1 is "+date1+" date2 is "+date2);
            }

             return date2.compareTo(date1);

        }

        @Override
           public int hashCode() {
                return this.url.hashCode();
            }

        @Override
        public boolean equals(Object obj) {

            SuggestionDetailBean suggestionDetailBean = (SuggestionDetailBean) obj;

            if(StringUtils.isEmpty(this.getTagList())){
                return this.getUrl().equals(suggestionDetailBean.getUrl());
            }
            else {
                return (this.getTagList().equals(suggestionDetailBean.getTagList())) &&
                        (this.getUrl().equals(suggestionDetailBean.getUrl()));
            }

        }

    }
Run Code Online (Sandbox Code Playgroud)

编辑:注意:如果我使用以下方法将hashset转换为树集:

 Set<SuggestionDetailBean> sortedSet = new TreeSet<SuggestionDetailBean>(hashset);
Run Code Online (Sandbox Code Playgroud)

然后保持正确的排序,因为重复的删除基于对象哈希码并且等于方法而不是比较方法.

rua*_*akh 15

根据Javadoc的TreeSet说法:

请注意,如果要正确实现接口,则由集合维护的排序(无论是否提供显式比较器)必须与equals一致Set.(参见ComparableComparator了解与equals一致的精确定义.)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用其compareTo(或 compare)方法执行所有元素比较,因此两个被认为相等的元素从集合的角度来看,方法是相等的.一套的行为 明确的,即使它的排序和equals不一致; 它只是不遵守Set界面的一般合同.

所以,问题在于你的compareTo方法:要么是给出不一致的结果,要么就是给出一致的结果,这些结果不符合当前a.compareTo(b) == 0和仅当的规则a.equals(b).

例如,这一位:

            if(this.date == null || other.date == null){
                return 0;
            }   
Run Code Online (Sandbox Code Playgroud)

意思是"如果有thisotherdate == null,然后报告this并且other相等",这当然不是你想要的.

  • @ user470184:如果在`HashSet`中执行所有重复数据删除,然后将这些元素复制到`TreeSet`,那么`TreeSet`将不包含重复项.但这不是真正正确的解决方案.正确的解决方法是纠正你的`compareTo`方法,以便`TreeSet`的"重复"概念与`HashSet`匹配. (4认同)