package com.collection.set;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
/*
集合的体系:
----| Collection: 单例集合的根接口
-------| List:实现了List接口的集合类,具备的特点:有序,可重复;
----------| ArrayList:底层是维护了一个Object数组实现的;特点:查询速度快,增删慢;
----------| LinkedList:底层是使用了链表数据结构实现的;特点:查询速度慢,增删快;
----------| Vector(了解即可):底层也是维护了一个Object数组实现的,与ArrayList是一样的;但是Vector是
线程安全的,操作效率低,所以被ArrayList取代了;ArrayList不是线程同步的,操作效率高;
-------| Set:实现了Set接口的集合类,具备的特点:无序,不可重复;
----------| HashSet:底层是使用了哈希表来支持的;特点:存取速度快;
HashSet的实现原理:
往HashSet中添加元素的时候,HashSet会先调用元素的hashCode()方法得到元素的哈希值,然后通过元素的
哈希值经过移位等运算,就可以算出该元素在哈希表中的存储位置;
元素的哈希值相当于元素在内存中的存储地址;
算出位置之后分两种情况存储:
情况一:
如果算出元素存储的位置目前没有其他任何元素存在,那么该元素可以直接存储到该位置上;
情况二:
如果算出该元素存储的位置目前已经存在别的元素了,那么HashSet会调用元素的equels方法与该位置
的元素再比较一次;如果equals返回的是true,那么该元素与这个位置上的元素就视为同一个元素,
不允许添加;如果equals返回的是false,那么该元素允许添加;
问题:哈希表中同一个位置可以添加多个元素吗?
可以。哈希表的其中一个特点:桶式结构。也就是说哈希表中的每个位置都相当于一个桶,可以存储多个元素;
----------| TreeSet:
无序:指添加元素和顺序和取出元素的顺序是不一致的;
*/
class Person{
int id;
String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "{id=" + id + ",name=" + name + "}";
}
@Override
public int hashCode() {
// 向HashSet中每添加一个元素就会调用一次元素的hashCode()方法;
System.out.println("===== 调用了hashCode()方法 =====");
// 重写hashCode()方法,使元素的id一样时,在哈希表中存储的是同一个位置;
return this.id;
}
@Override
public boolean equals(Object obj) {
// 重写equals,使id一样时,是同一个元素对象;
Person p = (Person)obj;
return this.id == p.id;
}
}
public class Demo5 {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void test1(){
Set set = new HashSet();
set.add("张三");
set.add("李四");
set.add("王五");
// 无序,不可以重复;
System.out.println("添加成功了吗?" + set.add("李四")); // 元素不可重复;添加失败,返回false;
System.out.println("集合中的元素:" + set); // 输出元素的顺序和添加元素的顺序是不一致的
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void test2(){
Set set = new HashSet();
set.add(new Person(1, "张三"));
set.add(new Person(2, "李四"));
set.add(new Person(3, "王五"));
/*
问题:此处元素能添加成功吗?
能。因为根据上面所说的HashSet的实现原理,此处新创建的Person对象的哈希值是唯一的,所以可以添加;
当重写hashCode()方法和equals()方法后,就不能添加成功了。
*/
System.out.println("添加成功了吗?" + set.add(new Person(2, "冯二")));
System.out.println("集合中的元素:" + set);
}
}