java集合:关于hashmap存储一个对象,中间改变对象的值,为什么再remove不能用新名字来删除
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不能用新名字来删除
打错了 展开
你重写了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;
}
你好,在hashset里面存储的是对象的地址还是对象?
我更改了book1的name之后这个对象在哈希表存储的位置变了吗?
谢谢
所有集合的底层都是数组或者指针(引用),所以集合存储里面肯定持有实例(跟对象还有区别)的地址啊,你name改了之后,产生的hashcode也改变了,掉的很大可能都是不一样散列桶了啊!