HashSet删除重复项但TreeSet没有?

时间:2013-02-13 22:30:53

标签: java hashset treeset

以下课程的输出是: 大小是3 大小是1

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

Set<SuggestionDetailBean> set = new TreeSet<SuggestionDetailBean>();

变为

Set<SuggestionDetailBean> set = new HashSet<SuggestionDetailBean>();

输出是: 大小是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()));
            }

        }

    }

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

 Set<SuggestionDetailBean> sortedSet = new TreeSet<SuggestionDetailBean>(hashset);

然后保持正确的排序,因为删除重复项基于对象哈希码和equals方法而不是compareto方法。

1 个答案:

答案 0 :(得分:15)

根据the Javadoc for TreeSet

  

注意由一组维护的排序(无论是否显式    提供比较器)如果是,则必须与equals 一致    正确实现Set接口。 (见Comparable    或Comparator以获得与一致的精确定义    等于。)这是因为Set接口定义在    equals操作的术语,但是TreeSet实例    使用compareTo执行所有元素比较(或    compare)方法,因此这个方法认为两个元素相等    从集合的角度来看,是平等的。一组的行为     即使它的排序与equals不一致,也是明确定义的;它    只是没有遵守Set接口的一般合同。

所以,问题出在你的compareTo方法上:要么是提供不一致的结果,要么就是提供一致的结果,这些结果不符合a.compareTo(b) == 0的规则,当且仅当{{1} }。

例如,这一位:

a.equals(b)

表示“如果 if(this.date == null || other.date == null){ return 0; } thisother,则报告date == nullthis相等”,这肯定不是您想要的