java hashset判重_Java中HashSet的重复性与判等运算重载

目录

另有一个故事……(平行天下篇)

这是一个关于另外一个平行天下——Java中的相似的故事……

文艺复兴.jpg……

另有一个优美的梦幻家园:java.util

在Java中,巧了,也有泛型的数据容器。不外,Java的容器和C#的组织方式有些差别,C#是单独开了一个System.Collections及子命名空间专门用于给容器类使用,而Java则是把容器连同其他的工具类一起丢到了java.util这一个大包中。

不外,容器的这部分内容似乎在Java里叫做JCF(Java Collections Framework)

而且,Java似乎不存在非泛型版本的容器,只管听说SE 5之前的容器普遍存在类型平安性问题(固然已经是过去了……),此外,Java还提供了对应于一些容器的功效接口(而且是泛型接口),利便自定义容器类型,例如,List是列表容器的接口而不是泛型容器,其对应的泛型容器是ArrayList:

Pigeon p = new Pigeon("咕咕咕"); // class Pigeon extends Bird

Cuckoo c = new Cuckoo("子规"); // class Cuckoo extends Bird

List birds = new List() { { add(p); add(c); } }; // 错误,List是容器接口,不能直接实例化

ArrayList flock = new ArrayList() { { add(p); add(c); } }; // 准确,这是一个泛型为Bird的ArrayList容器

List avians = new ArrayList() { { add(p); add(c); } }; // 准确,ArrayList实现了List,可视为List的多态

匿名内部类(AIC)

这个神奇的初始化写法在Java术语里叫做匿名内部类(AIC,Anonymous Inner Class),在Java中AIC是被普遍使用而且屡试不爽的,主要是用于简化Java代码。AIC的泛起使得从一个抽象的接口或抽象类(无法实例化,不提供实现)快速重构一个简朴详细类(可以实例化,具有实现)变得异常容易而无需另开文件去写类,而不会造成太大的性能影响(由于AIC是随用随丢的)。

不外AIC有个不算副作用的副作用,由于AIC往往需要实现(甚至可能是大量改写)接口或抽象类的方式,因此可能会在嵌套层数稀奇多的上下文中使得原本就对照杂乱的局势加倍杂乱(稀奇是接纳了欠妥的缩进计谋的时刻,由于AIC的写法本身在大多数情形下就包含了相当多的嵌套),导致代码可读性严重下降,看起来不是很直观,有碍观瞻。

此外,若是某个AIC频仍地泛起,那么AIC就不那么适用了,这种情形下建议把当前的AIC改成一个签字的类。

而且另有一个善战的达拉崩巴:HashSet

加倍巧合的是,在java.util里也有一个HashSet,功效也是作为一个哈希集使用,也就是说它也知足如下两点:

元素是唯一的

元素是无序的

What a COINCI-DANCE~~

而且,也是要分两种情形,值类型下,只要两个值相等,那么第二个元素就不会被添加:

int i = 5;

int j = 5;

HashSet integers = new HashSet();

integers.add(i); // i被添加到integers中

integers.add(j); // 没有转变,integers中已经有5了

而对于引用类型来说,和C#类似,也接纳引用一致性判断:

// 为了简朴这里不封装了,直接上字段

class Student {

public int id;

public String name;

public Student(int id, String name) {

this.id = id;

this.name = name;

}

}

public class Program {

public static void main(String[] args) {

Student s1 = new Student(1, "Tom");

Student s2 = new Student(2, "Jerry");

Student s3 = s1;

Student s4 = new Student(1,"Tom");

HashSet students = new HashSet();

students.add(s1); // s1被加入students中

students.add(s2); // s2被加入students中

students.add(s3); // 没有转变,s1已存在

students.add(s4); // s4被加入到students中,只管s4和s1长得一样,但引用不一致

}

}

我甚至是差不多拿上篇文章中的代码,险些没怎么改23333

然则,和上次一样的问题,只管s4和s1引用不一致,但现实场所下,我们倾向于把它们看成统一小我私家,那么怎么办呢??

另有另外一个故事(不是虚伪传说)

不是虚伪传说-序言

嗯,这个不是虚伪的故事,这就是正经的解决方案,放心大胆的读吧!!

另有一对涂满毒药的夺命双匕:equals和hashCode

固然,Java里所有工具都继续自java.lang.Object即Object,而Java工具也有两种相等判别方式:==和Object.equals。

而且,这俩判别方式一模一样,值类型下只要值相等就可以,而对于引用类型,==判别的是引用一致性。

然则为什么这次题目里没有==的故事了??

一直就没有,那是你的错觉,上一篇的==照样虚伪的故事呢,而且缘故原由也很简朴:

Java里运算符不允许重载。

而且Object里没有之前的ReferenceEquals,以是==就是引用一致性的兜底判别,没法重载的话那就免谈了,不外equals是父类方式,固然是可以重载的。

那hashCode呢??

和隔邻的System.Object.GetHashCode()类似地,这边也有一个java.lang.Object.hashCode(),作用也是类似的,返回一个用作哈希值的数。

而且加倍巧合的是,这里的Object.equals()和hashCode()也没什么关系,单独改写其中一个函数对另外一个函数也都没什么影响。

最最巧合的是,和隔邻一样,Java也建议equals和hashCode要改都改。

不外之前是由于非泛型容器(好比Hashtable),而这次是真真正正的为了泛型容器。

而HashSet正是使用equals和hashCode作为双重判据,HashSet以为equals返回true,且两者hashCode相等的时刻,就以为是相同的元素而不被

那把骑士圣剑呢??

异常遗憾,这里没有那种器械,java.util并没有提供类似于IEqualityComparer的器械,而HashSet也不提供getComparator()这种方式……

java.util只提供这个器械——interface Comparator,其作用和C#中的IComparer差不多,由于Java不让重载运算符,因此Comparator提供了compare方式举行的巨细对照,而且只是用于对照排序而已。

然后崩巴也准备开启营救公主的冒险

最后把程序改写成这个样子:

import java.util.HashSet;

class Student {

public int id;

public String name;

public Student(int id,String name) {

this.id = id;

this.name = name;

}

@Override

public boolean equals(Object obj) {

// TODO Auto-generated method stub

return id == ((Student)obj).id && name.equals(((Student)obj).name);

}

@Override

public int hashCode() {

return id;

}

}

public class HSetTest {

public static void main(String[] args) {

Student s1 = new Student(1,"Tom");

Student s2 = s1;

Student s3 = new Student(1,"Tom");

@SuppressWarnings("serial")

HashSet students = new HashSet() {

{

add(s1); // s1被添加到students中

add(s2); // 没有转变,s1已存在

add(s3); // 没有转变,s3被以为和s1逻辑上相等

}

};

for(Student s : students) {

System.out.println(String.format("%d.%s",s.id,s.name));

}

}

}

输出效果:

1.Tom

原文链接:https://www.cnblogs.com/oberon-zjt0806/p/12367370.html

本站声明:网站内容来源于网络,若有侵权,请联系我们,我们将及时处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值