import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test
{
public static void main(String[] args)
{
Set<Element> set = new HashSet<Element>();
Element i1 = new Element(1);
Element i2 = new Element(2);
Element i3 = new Element(3);
set.add(i1);
set.add(i2);
set.add(i3);
System.out.println("Before changed:");
printSet(set);
i1.setValue(2);
System.out.println(i1.equals(i2));
System.out.println("After changed:");
printSet(set);
}
public static void printSet(Set set)
{
Iterator it = set.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
}
class Element
{
private int value;
public Element(int value)
{
this.value = value;
}
public void setValue(int value)
{
this.value = value;
}
public int getValue()
{
return this.value;
}
@Override
public String toString()
{
return "" + this.value;
}
@Override
public boolean equals(Object obj)
{
if(this ==(Element)obj)
return true;
if (!(obj instanceof Element))
{
return false;
}
if (((Element) obj).getValue() == this.getValue())
{
return true;
}
return false;
}
@Override
public int hashCode()
{
return 37 + this.value;
}
}
在网上看到这个程序,这种先增加再修改的方法导致set有重复元素,是否违背了set的设计初衷呢
set.remove(i1);
printSet(set);
System.out.println("After add again");
set.add(i1);
printSet(set);竟然还可以重新添加,迷茫too....After remove
2, hashCode=39
3, hashCode=40
After add again
2, hashCode=39
2, hashCode=39
3, hashCode=40
只是这三个对象中的一个属性(value)的值有一样
然后他又重载了equals和hashCode方法
让equals方法打印出来的值为true来欺骗观众
………………
而已…………
以下摘自javaAPI java.lang.Object的hashCode方法说明:hashCode
public int hashCode()返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。
hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
返回:
此对象的一个哈希码值。
另请参见:
equals(java.lang.Object), Hashtable这个Element遵守了hashCode的规范了吗?
public boolean equals(Object obj)指示某个其他对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系: 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值 x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。 注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
参数:
obj - 要与之比较的引用对象。
返回:
如果此对象与 obj 参数相同,则返回 true;否则返回 false。
另请参见:
hashCode(), Hashtable
我觉得这是从概念上说,不能加,实际加了会破坏Set的概念。
基础上,对set规则的刻意破坏。set在添加元素时,依赖hashCode,
Equals两个函数的返回值。而楼主的用例,是在元素添加set以后,刻意去修还元素的数字以达到
修改hashCode,equals返回值,这是set出现“重复”也是自然的了。简单的说,set只在加入是会
检查数据的重复性,加入后就不管了(其实set也管不了)。
楼主的例子里的hashcode和equals是没问题的。
Oracle
Set只在add的时候保证唯一性,你add进来后再改Set就管不了了。
也就是说,Set中是可以存在非唯一性的情况的。
当然,正常情况下我们要避免add进来后再修改对象的值。
如果这个equlas返回true,那个Set集合就认为。这是同一个对像。不加进行添加操作。如果hashcode这个码不存在这个Set集合地址中。则直接添加到Set .而不进行equals操作。所以得出一个结论:
有相同hashcode的对像。可以存放在一个Set中,有相同equals的对像不能存放在同一个Set中。
set保证没有相同的对象 但是不能保证 没有2个拥有相同属性值的对象吧
坐等高人解答
add进来的时候是不等的,我add进来再把其中的一个值改成等于另一个值。懂了吗?
所以這種資料不應該是可修改的。
因此修改ID造成物件重複,應該算是設計產生的 bug。最後回到原問題 set中真的不能添加重复元素吗?
的確不能"添加"重複元素,但可以"修改"元素使其重複。
可以使用Set x = new HashSet(listInstance);的方式将有序重复的List转为无序不重复的~
反之却不怎么能~~
这样的hashCode还没有问题javaAPI的描述是hashCode在一次运行中值是不应该改变的,而这个value是个动态值,显然是不按协定来
set 乱序 list是顺序
我敢说你从来没有自己写过hashcode()方法,也根本不知道hashcode的意义。
自定义类的hashcode()就是要使用值而不是使用地址,这样才能真正的判断值的相等性而不是地址的相等性。懂?
Map是键值对形式的集合,好处是可以通过相应键找到相应的值,就好比一把钥匙开一把相应的锁。
set也是一种集合,其相邻的两个元素之间的有关系机制,好处是方便的横向的搜索相邻集合元素,但一旦删除其中的一个元素,则其相邻元素关系就得变更,不方便动态的添加和删除元素。
在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。看懂前提了吗?
你的发言暴露了你从来没有写过hashcode的真相。