Java 添加等效可变对象的HashSet
我知道我应该使公共类不可变,但在将Person对象添加到类型集Java 添加等效可变对象的HashSet,java,hashset,Java,Hashset,我知道我应该使公共类不可变,但在将Person对象添加到类型集HashSet之前,我已经更改了它的名称,并且我的Person类还实现了hashCode()和equals()方法,这些方法有助于检查对象是否与前一个对象相同,如果在hashCode()和equals()方法的帮助下是等效的,则可以防止将其添加到列表中,但输出仍然是: 上下快速移动 查理 鲍勃 而不是: 上下快速移动 查理 如果替换主类的代码段: Set<Person> set = new HashSet<Perso
HashSet
之前,我已经更改了它的名称,并且我的Person类还实现了hashCode()
和equals()方法,这些方法有助于检查对象是否与前一个对象相同,如果在hashCode()
和equals()方法的帮助下是等效的,则可以防止将其添加到列表中,但输出仍然是:
上下快速移动
查理
鲍勃
而不是:
上下快速移动
查理
如果替换主类的代码段:
Set<Person> set = new HashSet<Person>();
Person a= new Person("alice",45);
Person b=new Person("bob",41);
Person c= new Person("charlie",48);
set.add(a);
a.name="bob";
set.add(b);
set.add(c);
Set Set=newhashset();
人物a=新人(“爱丽丝”,45岁);
人员b=新人员(“bob”,41);
人员c=新人(“查理”,48岁);
增加(a);
a、 name=“bob”;
增加(b);
增加(c);
通过下面的代码(即,我直接声明了一个等价的对象,而没有像最初的问题代码那样更改名称):
Set Set=newhashset();
人员a=新人员(“bob”,45岁);
人员b=新人员(“bob”,41);
人员c=新人(“查理”,48岁);
增加(a);
增加(b);
增加(c);
然后不添加对象b
还有一点需要注意的是,在添加对象b之前,我更改了对象a的名称(在原始有问题的代码中),但它仍然在添加b为什么
我最初的有问题的代码包含主类和公共类,详细内容如下:
//Main.java class of generics_practice_test package;
package generics_practice_test;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
public class Main {
public static void main (String args[])
{
Set<Person> set = new HashSet<Person>();
Person a= new Person("alice",45);
Person b=new Person("bob",41);
Person c= new Person("charlie",48);
set.add(a);
a.name="bob";
set.add(b);
set.add(c);
for(Iterator<Person> iterator=set.iterator();iterator.hasNext();){
System.out.println(iterator.next());
}
}
}
//泛型的Main.java类\u实践\u测试包;
包装仿制药\实践\测试;
导入java.util.Set;
导入java.util.HashSet;
导入java.util.Iterator;
公共班机{
公共静态void main(字符串参数[])
{
Set=newhashset();
人物a=新人(“爱丽丝”,45岁);
人员b=新人员(“bob”,41);
人员c=新人(“查理”,48岁);
增加(a);
a、 name=“bob”;
增加(b);
增加(c);
for(Iterator Iterator=set.Iterator();Iterator.hasNext();){
System.out.println(iterator.next());
}
}
}
Person类的代码如下所示:
//下面是泛型\实践\测试包的人员类别
package generics_practice_test;
public class Person implements Comparable<Person> {
public String name;
public int age;
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String toString()
{
return this.name;
}
public int compareTo(Person o)
{
int myLength=name.length();
int oLength=o.name.length();
if(myLength == oLength) return 0;
if(oLength > myLength) return -1;
return 1;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
package-generics\u-practice\u-test;
公共类人员实现可比性{
公共字符串名称;
公共信息;
公众人物(字符串名称,整数年龄)
{
this.name=name;
这个。年龄=年龄;
}
公共字符串toString()
{
返回此.name;
}
公共内部比较(o人)
{
int myLength=name.length();
int-olelength=o.name.length();
如果(myLength==oleLength)返回0;
if(olelength>myLength)返回-1;
返回1;
}
@凌驾
公共int hashCode(){
最终整数素数=31;
int结果=1;
result=prime*result+((name==null)?0:name.hashCode();
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
if(obj==null)
返回false;
如果(getClass()!=obj.getClass())
返回false;
人员其他=(人员)obj;
if(name==null){
if(other.name!=null)
返回false;
}如果(!name.equals(other.name))
返回false;
返回true;
}
}
尝试将equals方法更改为此
@Override
public boolean equals(Object obj) {
if (obj == null) //first you check if object is null
return false;
if (getClass() != obj.getClass()) // then you check if object is of the same class
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
语句
if(this==obj)
按内存中的地址检查对象。每个对象在内存中的地址都会不同!如果在对象上使用了new
AHashSet
将根据hashCode
方法的结果存储元素。这是实现中使用的伪算法:
- 检索对象
。将其存储在hashCode
中int-possibleIndex
- 根据
获取可存储对象的索引。将其存储在possibleIndex
索引中
- 检索存储在
索引中的
。遍历此列表,并使用列表
方法查找对象是否不在此列表中。这样做是为了处理碰撞或具有相同equals
的对象hashCode
Person#hashCode
实现仅依赖于name
元素
让我们回顾一下您的第一段代码:
//create the new HashSet
Set<Person> set = new HashSet<Person>();
//create your elements to be inserted
Person a= new Person("alice",45);
Person b= new Person("bob",41);
Person c= new Person("charlie",48);
//try to add "a". It will calculate hashCode from name field,
//which value is "alice"
set.add(a);
//you change the name here, but it won't affect the previous
//operation because the index for "a" was calculated using "alice",
//not "bob" and IT WONT BE RECALCULATED!
a.name="bob";
//try to add "b". It will calculate hashCode from name field,
//which value is "bob"
//as noted before, there's no index based on "bob"'s hashCode,
//so it will be added with no problems
set.add(b);
//try to add "c". It will calculate hashCode from name field,
//which value is "charlie"
set.add(c);
//create the new HashSet
Set<Person> set = new HashSet<Person>();
//create your elements to be inserted
Person a= new Person("bob",45);
Person b=new Person("bob",41);
Person c= new Person("charlie",48);
//try to add "a". It will calculate hashCode from name field,
//which value is "bob"
set.add(a);
//try to add "b". It will calculate hashCode from name field,
//which value is "bob"
//since the index calculated from the hashCode of "bob" is
//already inserted, it will check if the element already exists
//Looking at Person#equals, which is based on name field only
//there is an element where the name field has a value of "bob"
//"b" won't be inserted
set.add(b);
//try to add "c". It will calculate hashCode from name field,
//which value is "charlie"
set.add(c);
HashSet
在内部使用HashMap
,HashMap是hashtable
数据结构的实现
Hashtables
uses有一个将数据存储在bucket中的概念
把它想象成一个映射,其中键是hashCode
,值是元素列表
现在这里发生的是,在存储时,它获取hashCode()
,并尽可能存储当前元素
在您的例子中,它是name
hashCode。现在以bob的哈希值为32为例,因此将有一个以32为键的条目,列表将包含该元素
您更改的名称并不会真正更改元素的位置
插入HashSet时,请遵循以下步骤
- 获取对象的hashCode值
- 用该值搜索bucket
- 如果找到了bucket,则遍历列表并使用当前对象对所有bucket调用equals
- 如果找到对象,则不要插入它,否则请插入它
a.name=“bob”
之后仍然添加b
,因为a
与其旧散列一起存储。更改a.name
会更改a.hashCode()
返回值,但包含的HashSet
无法知道这一点——因此a
仍使用其旧哈希(即
//create the new HashSet
Set<Person> set = new HashSet<Person>();
//create your elements to be inserted
Person a= new Person("bob",45);
Person b=new Person("bob",41);
Person c= new Person("charlie",48);
//try to add "a". It will calculate hashCode from name field,
//which value is "bob"
set.add(a);
//try to add "b". It will calculate hashCode from name field,
//which value is "bob"
//since the index calculated from the hashCode of "bob" is
//already inserted, it will check if the element already exists
//Looking at Person#equals, which is based on name field only
//there is an element where the name field has a value of "bob"
//"b" won't be inserted
set.add(b);
//try to add "c". It will calculate hashCode from name field,
//which value is "charlie"
set.add(c);