Java基础-Collection子接口之Set接口

                                    作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

 

 

  学习Collection接口时,记得Collection中可以存放重复元素,也可以不存放重复元素,那么我们知道List中是可以存放重复元素的。那么不重复元素给哪里存放呢?那就是Set接口,它里面的集合,所存储的元素就是不重复的。

 

 

一.Set接口的特点

  一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。在所有构造方法以及 addequalshashCode 方法的协定上,Set 接口还加入了其他规定,这些规定超出了从 Collection 接口所继承的内容。出于方便考虑,它还包括了其他继承方法的声明(这些声明的规范已经专门针对 Set 接口进行了修改,但是没有包含任何其他的规定)。 

  Set集合有多个子类,这么我们介绍其中的HashSet,LinkedHashSet这两个集合。Set结合取出元素的方式可以采用迭代器和增强for。

 

二.HashSet集合介绍

  此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。 总结HashSet有以下结果特点:

  1>.无序集合,也就是说存取元素和取出元素的顺序不一定是相同的;

  2>.没有索引;

  3>.不存储重复元素;

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 package cn.org.yinzhengjie.note;
 8 
 9 import java.util.HashSet;
10 import java.util.Iterator;
11 import java.util.Set;
12 
13 public class HashSetDemo {
14     public static void main(String[] args) {
15         Set<String> set = new HashSet<String>();
16         set.add("yinzhengjie");
17         set.add("尹正杰");
18         set.add("2018");
19         set.add("yinzhengjie");        //第二次添加同一个元素时,并不会放入HashSet集合中。
20         set.add("java");
21         set.add("Big Data");
22 
23         //用迭代器进行遍历
24         System.out.println("第一种遍历方式");
25         Iterator<String> it = set.iterator();
26         while(it.hasNext()) {
27             System.out.println("\t"+it.next());
28         }
29         
30         System.out.println("第二种遍历方式");
31         for (String string : set) {
32             System.out.println("\t"+string);            
33         }
34     }
35 }
36 
37 /*
38 以上代码执行结果如下:
39 第一种遍历方式
40     尹正杰
41     2018
42     java
43     Big Data
44     yinzhengjie
45 第二种遍历方式
46     尹正杰
47     2018
48     java
49     Big Data
50     yinzhengjie
51 */

 

三.哈希表的数据结构

  哈希表其实就是链表和数组的结合体。哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会根据这些对象的特有数据结合相应的算法,计算出这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组,即就是哈希表。

  当向哈希表中存放元素时,需要根据元素的特有数据结合相应的算法,这个算法其实就是Object类中的hashCode方法。由于任何对象都是Object类的子类,所以任何对象有拥有这个方法。即就是在给哈希表中存放对象时,会调用对象的hashCode方法,算出对象在表中的存放位置,这里需要注意,如果两个对象hashCode方法算出结果一样,这样现象称为哈希冲突,这时会调用对象的equals方法,比较这两个对象是不是同一个对象,如果equals方法返回的是true,那么就不会把第二个对象存放在哈希表中,如果返回的是false,就会把这个值存放在哈希表中。也就是说多个对象可能存放在同一块存储空间中,当第一个对象来到数组的存储空间时,这块空间存储的是第一个进入该区域的对象地址,当第二个对象再次进入这个空间时,这个对象的内存地址并不直接保存在数组中,而是保存在第一个存入的对象中。说道HashSet不得不说一下加载因子,所谓的加载因子就是一个触发数组扩容的指标。虚拟机默认是0.75,初始容量,数组长度默认是16。也就是说当数组的长度超过12时,就会扩容,而之前存在当前数组中的地址又会重新进行哈希。简图如下:

Java基础-Collection子接口之Set接口

2>.字符串对象的哈希值

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 package cn.org.yinzhengjie.note;
 8 
 9 class Teacher {
10     /*
11      * 没有做重写父类,每次运行结果都是不同整数
12      * 如果子类重写父类的方法,哈希值,自定义的
13      * 存储到HashSet集合的依据
14      * 
15      */
16     @Override
17     public int hashCode() {
18         return 100;
19     }
20 }
21 
22 public class HashDemo {
23     public static void main(String[] args) {
24         Teacher t = new Teacher();
25         //调用自定义的类的hashCode方法
26         int hashId = t.hashCode();
27         System.out.println(hashId);
28                 
29         String s1 = new String("abc");
30         String s2 = "abc";
31         System.out.println(s1.hashCode());
32         System.out.println(s2.hashCode());
33     }
34 }
35 
36 
37 /*
38 以上代码执行结果如下:
39 100
40 96354
41 96354
42 */

  我们可以明显看出自己定义的类调用hashCode()默认返回值为100,最终打印结果和我们预期的一样,而我们在创建一个字符串的时候,发现两个值相等的字符串他们的地址竟然也是一样的!这是怎么回事呢?这个时候我们就不得不去看一下String重写的hashCode源码啦。

Java基础-Collection子接口之Set接口

3>.哈希表的存储过程

 Java基础-Collection子接口之Set接口

四.哈希表的存储自定义对象

 1 /*
 2 @author :yinzhengjie
 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
 4 EMAIL:y1053419035@qq.com
 5 */
 6 
 7 package cn.org.yinzhengjie.note2;
 8 
 9 public class Person {
10     private String name;
11     private int age;
12     public String getName() {
13         return name;
14     }
15     public void setName(String name) {
16         this.name = name;
17     }
18     public int getAge() {
19         return age;
20     }
21     public void setAge(int age) {
22         this.age = age;
23     }
24     public Person(String name, int age) {
25         super();
26         this.name = name;
27         this.age = age;
28     }
29     public Person() {
30         super();
31     }
32     @Override
33     public String toString() {
34         return this.name + "---" + this.age;
35     }
36     @Override
37     public int hashCode() {
38         final int prime = 31;
39         int result = 1;
40         result = prime * result + age;
41         result = prime * result + ((name == null) ? 0 : name.hashCode());
42         return result;
43     }
44     @Override
45     public boolean equals(Object obj) {
46         if (this == obj)
47             return true;
48         if (obj == null)
49             return false;
50         if (getClass() != obj.getClass())
51             return false;
52         Person other = (Person) obj;
53         if (age != other.age)
54             return false;
55         if (name == null) {
56             if (other.name != null)
57                 return false;
58         } else if (!name.equals(other.name))
59             return false;
60         return true;
61     }    
62 }
Person.java 文件内容

相关文章:

  • 2021-12-16
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-04-26
  • 2021-08-24
  • 2021-04-23
猜你喜欢
  • 2021-09-18
  • 2021-12-24
  • 2021-12-05
  • 2021-04-08
  • 2021-11-21
相关资源
相似解决方案