------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、Set集合

  Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加

操作失败,add方法返回false,而新元素不会被加入。

  Set判断两对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用

equals方法比较返回true,Ser就不会接受这两个对象;反之,只要两个对象用equals方法比较

返回false,SEt就会接受这两个对象(甚至这两个对象是同一个对象,Set也可把它们当成两个对

象出来)。下面是使用普通Set的示例程序。

 import java.util.HashSet;
import java.util.Set; public class SetTest { public static void main(String[] args) {
Set names = new HashSet<>();
//添加一个字符串对象
names.add(new String("暨雪"));
//再次添加一个字符串对象
//因为两个字符串对象通过equals方法比较相等
//所以添加失败,返回false
boolean reasult = names.add(new String("暨雪"));
//从下面输出看到集合只有一个元素
System.out.println(reasult + "-->" + names);
} }

运行结果:

false-->[暨雪]

  从上面程序中可以看出,names集合两次添加的字符串对象明显不是同一对象(因为两次都调

用了new关键字来创建字符串对象),这两个字符串对象使用==运算符判断肯定返回false,但通过

equals方法比较将返回true,所以添加失败。最后结果输出只有一个元素。

1.HashSet类

HashSet是Set接口的典型实现,大多数时候使用Set集合是就是使用这个实现类。HashSet按Hash

算法来存储集合中的元素,因此具有很好的存取和查找性能。

  HashSet具有以下特点:

  1)不能保证元素的排序顺序,顺序有可能发生变化。

  2)HashSet不是同步的,如果多线程同时访问一个HashSet,假设有两个或两个以上线程同时

修改了HashSet集合时,则必须通过代码来保证其同步。

  3)集合元素值可以是null。

  HashSet集合判断两个以上相等的标准是两个对象通过equals()方法比较相等,并且两个对象的

hashCode()方法返回值也相等。

下面程序分别提供了三个类A、B和C,它们分别重写了equals()、hashCode()两个方法的一个或全部

,通过此程序可以看到HashSet判断集合元素相同的标准。

 import java.util.HashSet;

 public class HashSetTest {
//类A的equals方法总是返回true,但没有重写hashCode方法
static class A {
@Override
public boolean equals(Object o) {
return true;
}
}
//类B的hashCode总是返回1,但没有重写equals方法
static class B {
@Override
public int hashCode() {
return 1;
}
}
//类C重写了hashCode方法和equals方法
static class C {
@Override
public int hashCode() {
return 2;
}
@Override
public boolean equals(Object obj) {
return true;
}
} public static void main(String[] args) { HashSet names = new HashSet<>();
names.add(new A());
names.add(new A());
names.add(new B());
names.add(new B());
names.add(new C());
names.add(new C()); System.out.println(names);
} }

运行结果:

[HashSetTest$B@1, HashSetTest$B@1, HashSetTest$C@2, HashSetTest$A@7e5284e9, HashSetTest$A@12720f6c]

从上面程序可以看出,即使两个A对象通过equals()方法比较返回true,但HashSet依然把它们当成

两个对象;即使两个B对象的hashCode()返回相同值(都是1),但HashSet依然把它们当成同一个

对象。

注意:

 当把一个对象放入HashSet中时,如果需要重写该方法对应类的equals()方法,则也应该重写

hashCode()方法。其规则是:如果两个对象通过equals()方法比较返回true,这两个对象的hashCode

()值也应该相同。

  重写hashCode()方法的基本规则:

  1)在程序运行中,同一对象多次调用hashCode()方法应该返回相同的值。

  2)当两个对象通过equals()方法比较返回true时,这两个对象的hashCode()方法应返回相等的值。

  3)对象中用作equals()方法比较标准的Filed,都应该用计算hashCode值。

hashCode返回值的计算:

return f1.hashCode() + (int) f2;

为了避免直接相加产生偶然相等(两个对象f1、f2Field并不相等,但他们的和恰好相等),

可以通过为个Field乘以任意一个质数后在相加。

return f1.hashCode() * 17 + (int) f2 * 13;

  如果向HashSet中添加一个可变对象后,后面出现修改了该可变对象的Field,则可能导致

它与集合中的其他元素相同(即两个对象通过equals()方法比较返回true,两个对象的

hashCode()值也相等)。这就有可能导致HashSet中包含两个相同的对象。下面程序演示了这

种情况。

 import java.util.HashSet;
import java.util.Iterator; class R {
int count;
public R (int count){
this.count = count;
}
@Override
public String toString() { return "R[count:" + count + "]";
}
@Override
public boolean equals(Object obj) { if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == R.class) {
R r = (R) obj;
if (r.count == this.count) {
return true;
}
}
return false;
}
@Override
public int hashCode() { return this.count;
}
}
public class HashSetTest2 { public static void main(String[] args) { HashSet hs = new HashSet<>();
hs.add(new R(5));
hs.add(new R(-3));
hs.add(new R(9));
hs.add(new R(-2));
//打印HashSet集合,集合没有重复
System.out.println(hs);
//取出第一个元素
Iterator it = hs.iterator();
R first = (R) it.next();
//为第一个元素的count实例变量赋值
first.count = -3;
//再次输出HashSet集合,集合元素有重复元素
System.out.println(hs);
//删除count为-3的R对象
hs.remove(new R(-3));
System.out.println(hs);
System.out.println("hs是否包count为-3的R对象?" + hs.contains(new R(-3)));
System.out.println("hs是否包count为5的R对象?" + hs.contains(new R(5)));
System.out.println("hs是否包count为9的R对象?" + hs.contains(new R(9)));
} }

运行结果:

[R[count:5], R[count:9], R[count:-3], R[count:-2]]
[R[count:-3], R[count:9], R[count:-3], R[count:-2]]
[R[count:-3], R[count:9], R[count:-2]]
hs是否包count为-3的R对象?false
hs是否包count为5的R对象?false
hs是否包count为9的R对象?true

  上面程序中的first.count = -3;因为改变了HashSet集合中第一个R对象的count实例变量

的值,这将导致该R对象与集合中的其他对象相同。当试图删除count = -3的R对象时,HashSet

会计算出该对象的hashCode值,从而找出该对象在集合中保存位置,然后把此处的对象与count

为-3的R对象通过equals()方法进行比较,如果相等则删除该对象——HashSet只有第三元素才

满足该条件(第一个元素实际上保存在count为5的R对象对应的位置),所以第三个元素被删除

。至于第一个count为-3的R对象,它保存在count为5的R对象对应的位置,但是用equals()方法

拿它和count为5的R对象比较时有返回false——这将导致HashSet不可能准确访问该元素。

  

Java——(三)Collection之Set集合、HashSet类的更多相关文章

  1. Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类

    Collection 之 Set 实现类: HashSet TreeSet 特点: 无序. 元素不可重复. (如果试图添加一个已经有的元素到一个Set集合中,那么会添失败,add()方法返回false ...

  2. Java——(四)Collection之Set集合TreeSet类

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- TreeSet类 TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗 ...

  3. Java笔记(二十四)……集合工具类Collections&Arrays

    Collections 集合框架的工具类,方法全部为静态 Collections与Collection的区别 Collection是集合框架的一个顶层接口,里面定义了单列集合的共性方法 Collect ...

  4. Java中Collection、Map常用实现类研究分析

    接口/实现类 描述 key是否可为null 为null是否报错 key是否重复 key重复是否报错 key是否和添加一致 是否线程安全 List 一组元素的集合 ArrayList 基于数组存储,读取 ...

  5. java的collection集合

    # 原创,转载请先留言 1.集合的由来 数组的长度是固定的,当需要增加或减少元素时需要对数组重新定义,太麻烦了.java内部给我们提供了集合类,能存储任意对象,长度可以改变的,随着元素的增加而增加,随 ...

  6. Java中Collection和Collections的区别(引用自:http://www.cnblogs.com/dashi/p/3597937.html)

      1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对象进行基本操作的通用接口方法.Collection接口在Java 类库中有很多具体的实现.Co ...

  7. java类库 collection与collections (转)

    http://www.cnblogs.com/dashi/p/3597937.html Java中Collection和Collections的区别 1.java.util.Collection 是一 ...

  8. Java中Collection和Collections的区别(转载)

    转载来源:http://www.cnblogs.com/dashi/p/3597937.html 1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对 ...

  9. 复习java基础第三天(集合:Collection、Set、HashSet、LinkedHashSet、TreeSet)

    一.Collection常用的方法: Java 集合可分为 Set.List 和 Map 三种体系: Set:无序.不可重复的集合. List:有序,可重复的集合. Map:具有映射关系的集合. Co ...

随机推荐

  1. Spring MVC源码分析(续)——请求处理

    转自:http://blog.csdn.net/shi1122/article/details/8041017 (转移位置了,时光隧道:http://www.jmatrix.org/spring/50 ...

  2. Application(全局对象,ViewState

    Application对象生存期和Web应用程序生存期一样长,生存期从Web应用程序网页被访问开始,HttpApplication类对象Application被自动创建,直到没有一个网页被访问时结束, ...

  3. 浅析Linux操作系统工作的基础

    环境:lubuntu 13.04   kernel 3.9.7 作者:SA12226265 katao 简介: 本文根据 Linux™ 系统工作基础的分析,对存储程序计算机.堆栈(函数调用堆栈)机制和 ...

  4. struts.enable.DynamicMethodInvocation = true 动态方法调用

    default.properties 在Struts 2的核心jar包-struts2-core中,有一个default.properties的默认配置文件.里面配置了一些全局的信息,比如: stru ...

  5. 根据http协议传送数据

    发送的内容: [50 4f 53 54 20 2f 64 65 78 2f 66 69 72 65 70 6f 77 65 72 20 48 54 54 50 2f 31 2e 31 0d 0a 43 ...

  6. [BZOJ 3942] [Usaco2015 Feb] Censoring 【KMP】

    题目链接:BZOJ - 3942 题目分析 我们发现,删掉一段 T 之后,被删除的部分前面的一段可能和后面的一段连接起来出现新的 T . 所以我们删掉一段 T 之后应该接着被删除的位置之前的继续向后匹 ...

  7. [BZOJ 1034] [ZJOI2008] 泡泡堂BNB 【贪心】

    题目链接:BZOJ - 1034 题目分析 这道题和田忌赛马的典故很相似. 先要将两队的队员都按照水平从小到大分别排序. 然后每次尝试用我方最弱的队员赢对方最弱的队员,或者用我方最强的队员赢对方最强的 ...

  8. 在objc项目中使用常量的最佳实践

    在objc项目中使用常量的最佳实践   之前,在在objc项目中使用常量中,使用c的预处理#define来设置常量.比如,可以做个头文件,然后在需要的类文件中import,使用常量. 但这不是最佳实践 ...

  9. Node.js权威指南 (8) - 创建HTTP与HTTPS服务器及客户端

    8.1 HTTP服务器 / 177 8.1.1 创建HTTP服务器 / 177 8.1.2 获取客户端请求信息 / 182 8.1.3 转换URL字符串与查询字符串 / 184 8.1.4 发送服务器 ...

  10. 使用QJM部署HDFS HA集群

    一.所需软件 1. JDK版本 下载地址:http://www.oracle.com/technetwork/java/javase/index.html 版本: jdk-7u79-linux-x64 ...