Set 一个不包含重复元素的 collection。更正式地说,set 不包含满足 e1.equals(e2)
的元素对 e1
和 e2
,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。
数学概念集合:一定范围的,确定的,可以区别的事物,当作一个整体来看待,就叫做集合,简称集,其中各事物叫做集合的元素或简称元。
HashSet
@Test
public void testFor() {
Set<String> sets = new HashSet<String>();
sets.add("1");
sets.add("2");
sets.add("3");
sets.add("4");
sets.add("5");
for (String str : sets) {
System.out.println(str);
}
// s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
}
这段代码到输出顺序是:3,2,1,5,4。而且输出顺序有固定的,也就是说String的HashCode是和它的值一一映射的,而且不好整顺序。
@Test
public void testFor2() {
Set<Integer> sets2 = new HashSet<Integer>();
sets2.add(1);
sets2.add(2);
sets2.add(3);
sets2.add(4);
sets2.add(5);
for (Integer i : sets2) {
System.out.println(i);
}
// value
}@Test
public void testFor3() {
Set<Integer> sets3 = new HashSet<Integer>();
sets3.add(5);
sets3.add(4);
sets3.add(3);
sets3.add(2);
sets3.add(1);
for (Integer i : sets3) {
System.out.println(i);
}
// value
}
这两段代码的输出一样的顺序:1,2,3,4,5。原因在与Integer的HashCode是该整型常量的值。
@Test
public void testFor4() {
Set<User> users = new HashSet<User>();
User user1 = new User();
user1.setId("user1");
users.add(user1);
User user2 = new User();
user2.setId("user2");
users.add(user2);
for (User user : users) {
System.out.println(user.getId());
System.out.println(user.hashCode());
}
// public native int hashCode();
}
这段代码的输出顺序不固定,User的HaseCode每次执行都在变化,HashCode是由本地代码提供的,它的值和对象的内存地址有关系。
从上面几段代码可以得出结论:HashSet的存储顺序由Hash值的大小决定。
Java语言规范规定如下:
- 两个对象equals(),hashCode()值相同
- 两个对象不equals(),hashCode()可以相等,如果hashCode()不相等,可以提高Hash查找的性能。
下面的代码是合法的,但是Hash查找的性能等于ListList查找的性能。
@Override
public int hashCode() {
return 42;
}
hashCode简单的实现方法:
- 确定整型散列码
- 域是boolean类型,计算(f ? 0 : 1)
- 域是byte,char,short,int,计算int()f
- 域是long,计算(int)(f ^ ( f >>> 32))
- Why
- 域是float,计算Float.floatToIntBits(f)
- 域是double,计算Double.doubleToLongBits(f),GoTo long
- 域是对象,调用hashCode()
- 域是null,返回0
确定了以上的属性hashCode
@Override
public int hashCode() {
int result = 17;
result = 31 * result + code1;
result = 31 * result + code2;
result = 31 * result + code3;
return result;
}
17是随意选的,选择31的原因是:
- 31即使乘法溢出,信息仍然可以保持
- VM优化,31 * i = (i << 5) – i
TreeSet
<!-- Generated by javadoc (build 1.6.0-beta2) on Thu Jan 11 21:34:52 CST 2007 -->
<script type="text/javascript"></script>
<noscript></noscript>