TreeSet,HashSet排序和去重的坑

先看下面一段代码:

package 类集;
import java.util.Set;
import java.util.TreeSet;
class Person{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String gtoString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
};

public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new TreeSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;
        System.out.println(allSet) ;
    }
};

运行结果:

Exception in thread "main" java.lang.ClassCastException: 类集.Person cannot be cast to java.lang.Comparable
    at java.util.TreeMap.compare(TreeMap.java:1294)
    at java.util.TreeMap.put(TreeMap.java:538)
    at java.util.TreeSet.add(TreeSet.java:255)
    at 类集.test1.main(test1.java:19)

报错。此时没有排序,因为java.lang.comparable类导致

一个对象要排序,对象本身必须继承comparable接口。

String、Long等类型已经实现了此接口,所以可以直接对这些类型直接进行排序。源码如下:

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
}

修改如下:

package 类集;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable<Person>{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
    public int compareTo(Person per){  //这里需要复习comparable接口的知识
        if(this.age>per.age){
            return 1 ;
        }else if(this.age<per.age){
            return -1 ;
        }else{
            return 0 ;
        }
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new TreeSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:赵六;年龄:33]

此时发现,王五是被去重了。但是孙七也没有插入进来,因为comparable根据年龄进行比较,认为年龄只要33岁,都是重复的,所以看到孙七没有插入进来。

此时我们比较的时候,不仅要比较年龄,还要比较姓名。改进代码:

package 类集;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable<Person>{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
    public int compareTo(Person per){
        if(this.age>per.age){
            return 1 ;
        }else if(this.age<per.age){
            return -1 ;
        }else{
            return this.name.compareTo(per.name) ;    // 调用String中的compareTo()方法
        }
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new TreeSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:孙七;年龄:33, 姓名:赵六;年龄:33]

此时的去重并不是真正意义上的去重。根据我们写的代码,只有年龄一样&&姓名一样才会认为重复。

如果我想按年龄排序,但是呢按名字去重,TreeSet是做不到的!仔细体会

只能借助HashSet来去重,用TreeSet按年龄排序(不按年龄去重,就不要return 0,return 0 就会被认为重复)

HashSet去重要点:

  1. 重写hashcode()方法
  2. 重写equals()方法
package 类集;
import java.util.HashSet;
import java.util.Set;
class Person{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public boolean equals(Object obj){    // 覆写equals,完成对象比较
        if(this==obj){
            return true ;
        }
        if(!(obj instanceof Person)){
            return false ;
        }
        Person p = (Person)obj ;    // 向下转型
        if(this.name.equals(p.name)&&this.age==p.age){
            return true ;
        }else{
            return false ;
        }
    }
    public int hashCode(){
        return this.name.hashCode() * this.age    ; // 自己定义一个公式,如上所写。
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new HashSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;    
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:赵六;年龄:33, 姓名:王五;年龄:32, 姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:孙七;年龄:33]

没有了年龄重复的元素!

 

如果要想使用Set,必须注意以上两个问题.

  1. Set接口依靠hashCode()和equals()完成重复元素的判断
  2. TreeSet依靠Comparable完成排序的操作
  3. TreeSet不可以按照a字段去重,按b字段排序。只可以按a排序和去重(不想去重,就不要在方法中写return 0)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值