java集合:关于hashmap存储一个对象,中间改变对象的值,为什么再remove不能用新名字来删除

代码如下:publicclassDemo1{publicstaticvoidmain(String[]args){HashSet<book>sc=newHashSet<>... 代码如下:
public class Demo1 {
public static void main(String[] args) {
HashSet<book> sc =new HashSet<>();
book book1=new book("java书2",18);
book book2=new book("java书",99);
sc.add(book2);
sc.add(book1);
System.out.println("原始"+sc);
Iterator<book> it = sc.iterator();
while(it.hasNext()) {
book next = it.next();
if(next.name.equals("java书")) {
next.name="java神书";

}
}
System.out.println("更改名字之后"+sc);

sc.remove(book2);
System.out.println("删除book2之后"+sc);

}
}
class book{
String name;
int price;

public book() {
super();
}

public book(String name, int price) {
super();
this.name = name;
this.price = price;
}

@Override
public String toString() {
return "【书名:"+name+",价格"+price+"】";
}

// @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + price;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
book other = (book) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (price != other.price)
return false;
return true;
}

}
输出的结果如下:
原始[【书名:java书,价格99】, 【书名:java书2,价格18】]
更改名字之后[【书名:java神书,价格99】, 【书名:java书2,价格18】]
删除book2之后[【书名:java神书,价格99】, 【书名:java书2,价格18】]

这个是为什么删不了呢?
另外的疑问:在hashset里面存储的是地址还是值?
更改了对象的成员属性在哈希表里面的位置变了吗?
问题是关于hashset存储一个对象,中间改变对象的值,为什么再remove不能用新名字来删除
打错了
展开
 我来答
幻形术
2018-06-22 · TA获得超过1262个赞
知道小有建树答主
回答量:994
采纳率:81%
帮助的人:264万
展开全部
这个得看hashset的源码了,内部会以hashcode或其经过某种算法得到的二次hash值为key来组织存储数据。

你重写了book的hashcode方法,并且内部用到了name来计算hashcode,那么当你修改了name后,它的hashcode自然变了,那么它就在原来的hashset里找不到了,自然删除不掉。
追问
你好,在hashset里面存储的是对象的地址还是对象?
我更改了book1的name之后这个对象在哈希表存储的位置变了吗?
谢谢
追答

你是学过C/C++吗?怎么老在说地址和对象?在java里这样问我也不知道怎么回答你。老实说我并不是搞java开发的,只是了解其一些东西。我就是C++的,如果你真问我hashset里存的是地址还是对象,我只能说存的是引用,算C/C++里面的地址吧。但是hash结构类内部并不是直接拿对象引用(地址)来定位对象的,而是hashcode.

这个要看hashset、hashmap、hashtable的源码。看别人博客上的吧:网页链接

这几种hash结构内部大致类似,存的是对象的引用是肯定的,hash最基本的原理就是通过hash值为key来定位value对象引用,所以它内部同时记录了hashcode二次hash值和对象引用(看上面博客),内部有一个数组存储对象,但是用hashcode二次hash值作为数组索引,当你remove一个对象的时候,内部是先取得对象的hashcode,计算二次hash值当数组索引下标,在数组中找到对应的hash桶,再在hash桶中遍历所有对象看是否有与remove传入的参数equal的,有就算命中找到能删除,找不到就删除不了了。

现在问题就是你重写了book类的hashcode方法,导致其hashcode变了,那么其二次hash值也变了,但hashset内部定位到了其它的或者根本不存在的数组元素也就是hash桶,自然找不对你想删除的对象。

public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode()); //用到了被修改的name
result = prime * result + price;
return result;
}
嘴角上o扬
2018-06-22
知道答主
回答量:15
采纳率:33%
帮助的人:4.6万
展开全部
楼上已经说的很清楚了啊。hashSet也是通过hashMap存储的,不过进行了一些包装,使用hashset、hashMap因为存放和比较需要通过hashcode方法和equals方法所以要重写啊。你上面代码里面存入book2的名称都改了,remove的时候BOOK类计算出的hashcode值肯定找不到啊。不行你再定义book1、book2的时候把java书2、java书上下换一下就能删掉了。还有大批量数据的时候,hashSet的性能很差的 。
追问
你好,在hashset里面存储的是对象的地址还是对象?
我更改了book1的name之后这个对象在哈希表存储的位置变了吗?
谢谢
追答
所有集合的底层都是数组或者指针(引用),所以集合存储里面肯定持有实例(跟对象还有区别)的地址啊,你name改了之后,产生的hashcode也改变了,掉的很大可能都是不一样散列桶了啊!
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式