第一点,Set集合中是不允许有重复元素的,
第二点,Set集合中是无顺序的
第三点:
* 为什么 add方法在添加String类型和普通的对象Person的时候结果不太一样,在它的帮助文档中是这样解释的
* //Adds the specified element to this set if it is not already present. More formally,
* adds the specified element e to this set if this set contains no element e2
* such that (e==null ? e2==null : e.equals(e2)).
* If this set already contains the element, the call leaves the set unchanged and returns false.
可以看到,对于增加一个非空对象e,首先要保证集合中不存在一个对象,其地址和e相同,同时要满足在存在的集合中不存在e2 使得 e.equals(e2)成立,
那么这个就可以解释了,对于String对象,equals方法比较的是内容,所以只有一个a被添加到set中
对于Person对象,equals方法比较的是地址,所以两个对象都会被添加到Set中
*/
关于第三点的更详细的原理解释:
当使用HashSet 时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code 值是否与增加的对象的 hash code 值一致;如果不一致,直接加进去;如果一致,再进行 equals 方法的比较,equals 方法如果返回 true,表示对象已经加进去了,就不会再增加新的对象,否则加进去
// 举几个例子更加了解上面说的几点
import java.util.HashSet;
public class HashSetTest {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
// 第一点,Set集合中是不允许有重复元素的,
// 第二点,Set集合中是无顺序的
hashSet.add("a");
hashSet.add("b");
hashSet.add("c");
hashSet.add("d");
hashSet.add("a");
System.out.println(hashSet); // d b c a
/*第三点:
* 为什么 add方法在添加String类型和普通的对象Person的时候结果不太一样,在它的帮助文档中是这样解释的
* //Adds the specified element to this set if it is not already present. More formally,
* adds the specified element e to this set if this set contains no element e2
* such that (e==null ? e2==null : e.equals(e2)).
* If this set already contains the element, the call leaves the set unchanged and returns false.
可以看到,对于增加一个非空对象,首先要保证两个对象的地址是不一致的才能添加,
同时要满足在存在的集合中不存在e2 使得 e.equals(e2)成立,
那么这个就可以解释了,对于String对象,equals方法比较的是内容,所以只有一个a被添加到set中
对于Person对象,equals方法比较的是地址,所以两个对象都会被添加到Set中
*/
/*
* 当使用HashSet 时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code 值
* 是否与增加的对象的 hash code 值一致;如果不一致,直接加进去;
* 如果一致,再进行 equals 方法的比较,equals 方法如果返回 true,
* 表示对象已经加进去了,就不会再增加新的对象,否则加进去
*/
//对于String类型,它重写了hashCode()方法, 它的hashcode值的计算方法如下:
// The hash code for a String object is computed as
// s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
hashSet.clear();
String s1= new String("a");
String s2=new String("a");
// 因此在添加String的时候,s1和s2的hashcode值是一样的,之后就回去比较equals方法,也一样,所以不添加
hashSet.add(s1);
hashSet.add(s2);
System.out.println(hashSet); //[a]
hashSet.clear();
People people1 =new People("zhangsan");
People people2 =new People("lisi");
// 在添加People的时候,people1和people2的hashcode值是不一样的,因此添加到hashSet中去
hashSet.add(people1);
hashSet.add(people2);
System.out.println(hashSet); //[Set.People@3e2de41d, Set.People@36db4bcf]
}
}
知识点介绍:equals 方法一旦被重写,hashcode方法也一定要被重写,反之亦然。
equals方法的特性:
a) 自反性:x.equals(x)应该返回 true
b) 对称性:x.equals(y)为 true,那么y.equals(x)也为true。
c) 传递性:x.equals(y)为 true 并且y.equals(z)为true,那么 x.equals(z)也应该为 true。
d) 一致性:x.equals(y)的第一次调用为 true,那么 x.equals(y)的第二次、第三次、第 n次调用也应该为true,前提条件是在比较之间没有修改 x 也没有修改 y。
e) 对于非空引用 x,x.equals(null)返回false。
hashcode()方法特性:
a) 在 Java 应用的一次执行过程当中,对于同一个对象的 hashCode 方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化) 。
b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的。
c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,可以不同) ,但是如果不同则可以提高应用的性能。
d) 对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址,它会把地址转化为一个整数) 。
//Object类中你的源代码, native代表着这是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI(java native interface)接口调用其他语言来实现对底层的访问。
public native int hashCode();
// equals方法源代码
public boolean equals(Object obj) {
return (this == obj);
}
// toString() 方法源代码,Object类的toString返回: 类名+@+对象的地址(转化为16进制的整形字符串)
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
如果想实现一个功能:People类根据名字来进行能否加到hashSet中去的一个判断依据, 即如果两个People对象名字相同,那么只能允许一个对象添加到hashSet中去,
实现方法,重写equals和hashCode 方法,记住这两个方法是要一起重写的,一个被重写,另一个也要被重写, 有两种重写方式,一个是自己重写,一个系统自动生成,下面代码中有介绍
class People {
String name;
String age;
public People(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
// 可以自己重写方法
public int hashCode() {
return this.name.hashCode();
}
public boolean equals(Object obj) {
if (this == obj){ // 判断地址是否相同
return true;
}
if (obj == null){ // 判断是否为空
return false;
}
if (obj instanceof People){ // 是否是People对象
People people = (People) obj;
if(this.name.equals(people.name)){
return true;
}
}
return false;
}
// eclipse 提供了自带的生成的办法,方便快捷,通过点击 Source----Generate hashCode() and equals()
// @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;
// People other = (People) obj;
// if (name == null) {
// if (other.name != null)
// return false;
// } else if (!name.equals(other.name))
// return false;
// return true;
// }
}