Hash重写equels和Hashcode方法去重,TreeSet重写比较器去重排序

Set 接口实现类中的HashSet,TreeSet。

集合中不允许出现重复,去重的实现
1.HashSet

a.基本数据类型 HashSet是由哈希算法来实现的,在一个对象要被添加到集合中的时候,会被系统分配一个哈希值,使用的是hashCode()方法,系统首先会根据这个对象的哈希值去和集合中的对象去比较,

如果哈希值不同就可以加入,

如果相同,就去比较俩字符串的值是否一样,使用equals()方法,如果一样就不能加入,

此时,重复的对象是无法加入HashSet的。

b.引用类型数据 当我们加入的对象是数据类型不是基本数据类型(int,char,double 等),

下面我们在HashSet集合中添加三个Student类的对象

  HashSet<Student> hashSet = new HashSet<>();
   hashSet.add(new Student("张三", 18));
   hashSet.add(new Student("李四", age));
   hashSet.add(new Student("张三", 18));
   System.out.println(hashSet);

输出的结果是:

[Student [name=张三, age=18], Student [name=张三, age=18], Student [name=李四, age=19]

可以看出,俩张三都被添加进去了,但是重复的我们并不想添加进去,为什么会被添加进去呢
这时因为在创建student的时候,我们给每个对象都在堆内存中开辟了一片空间,虽然俩对象中的元素相等,但是他们的地址是不一样的,所以系统认为他们是不同的,所以被添加进去了
如果我们要让系统把student中重复的去掉,我们只能从底层去操作,因为HashSet是系统内部根据比较Hash值来判断的,然后在调用equals方法来比较的,所以我们要重写Object类中的hashCode和equals方法
因为我们要对Student类的对象排序,自然是Student类的对象来调用,所以在Student类中进行方法的重写

 //重写hashCode方法
 @Override
    public int hashCode()
//这里返回的是要添加的对象的哈希值
    {
        return 1;
    }
//重写equals方法
 @Override
    public boolean equals(Object obj)
 {
     Student student = (Student)obj;
     if (student.name.equals(this.name)&&student.age == this.age)
     {
        return true;
     }
        return false;
    }
}

再次运行,输出的结果是:

[Student [name=张三, age=18], Student [name=李四, age=19]]

这次可以看出重复的对象已经被去除了.

2.TreeSet

TreeSet是Set的一个实现类,底层是由二叉树实现的

a.基本数据类型
创建一个TreeSet类型的集合,并将几个整数装进去

TreeSet<Integer> treeSet = new TreeSet<>();
    treeSet.add(10);
    treeSet.add(8);
    treeSet.add(15);
    treeSet.add(11);
    treeSet.add(8);
    System.out.println(treeSet);

输出的结果是

[8, 10, 11, 15] //我们可以根据输出的结果看出TreeSet会将对象排序并将重复的删除了

HashSet的作用就是去除重复的对象,而TreeSet的主要作用就是排序compareTo(obj) 方法
b. 引用类型数据
例:在TreeSet中添加四个学生类对象

  TreeSet<Student> treeSet = new TreeSet<>();
       treeSet.add(new Student("张三", 18));
       treeSet.add(new Student("李四", 19));
       treeSet.add(new Student("张三", 18));
       System.out.println(treeSet);

当我们运行的时候,会发现系统会报错,这是因为我们添加进去的Student类,不是系统类,系统不知道怎么排序,所以会报错
我们写系统类之所以系统会排序,是因为系统类中都实现了Comparable接口中的比较的抽象方法,系统在add的时候,要添加的系统对象会调用这个比较方法,进行排序和去除重复的对象
所以我们需要在Student类中实现接口,重写接口中的比较方法

//重写comparable接口中的抽象方法,主要是把对象的排序的规则写进去
@Override
//要注意的是当返回值为0的时候,系统就会认为俩值是一样的,就不会添加该对象
    public int compareTo(Student o) {
        // TODO Auto-generated method stub
    int ageNum = this.age - o.age;
    int nameNum = this.name.compareTo(o.name);
    //当年龄一样的时候,我们就比较俩者的姓名
    return ageNum == 0 ? nameNum :ageNum;
    }

运行得到的结果是:

[Student [name=张三, age=18], Student [name=李四, age=19]]

可以看出我们的运行结果已经根据年龄排序了,但是这种方法有一个局限,如果该类的对象被装到俩集合中,排序的条件不同,这样的话就没法重写抽象方法了.

c.同一类对象装在不同集合中 ,排序的条件不同,没法重写抽象方法

同一类对象在不同集合中,这时候我们可以为每一个集合创建一个比较器Comparator,用比较器来排序
我们这里要用到接口Comparator中的比较方法,我们需要给Comparator接口写一个实现类,在类中重写抽象方法 compare(),方法中也是用来写排序的规则的

public class StudentImpl implements Comparator<Student> {
	 @Override
	public int compare(Student o1,Student o2)
	 {
	   int intNum = o1.getAge() - o2.getAge();
	   int nameNum = o1.getName().compareTo(o2.getName());
	   return nameNum == 0 ? intNum :nameNum;
	}
}

在实现了comparator接口后,我们根据其实现类来为TreeSet创建一个比较器

TreeSet<Student> treeSet = new TreeSet<>(new StudentImpl());
   treeSet.add(new Student("张三", 18));
   treeSet.add(new Student("李四", 19));
   treeSet.add(new Student("张三", 18));
   System.out.println(treeSet);

输出的结果是:

[Student [name=张三, age=18], Student [name=李四, age=19]]

这样即使student类被装到很多个集合中,并且排序的条件不同,我们也可以为每一个集合创建一个特有的比较器来比较

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值