文章目录
1,Java集合子接口之Set接口
- Set接口是Collection的子接口,set接口没有提供额外的方法
- Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。
- Set 判断两个对象是否相同不是使用==运算符,而是根据equals()方法
1.1,Set接口实现类的对比
* 1.Set接口的框架:
* |----Collection接口:单列集合,用来存储一个一个的对象
* |----Set接口:存储无序的、不可重复的数据 -->高中讲的“集合”
* |----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
* |----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照
* 添加的顺序遍历对于频繁的遍历操作,LinkedHashSet效率高于HashSet.
* |----TreeSet:可以按照添加对象的指定属性,进行排序。
*
1.2,Set的无序性与不可重复性的理解
- Set:存储无序的,不可重复的数据
1.无序性: 不等于随机性,存储的数据在底层数组中并非按照数组索引的顺序添加。而是根据数据的hash值决定的
2.不可重复性:保证添加的元素按照equals方法判断时不能返回true,即相同的元素只能添加一个
import org.junit.Test;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 1.Set接口中没有定义额外的方法,使用的都是Collection中声明过的方法。
*/
public class SetTest {
/**
* 一、Set:存储无序的、不可重复的数据
* 1.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。
* 2.不可重复性:保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一个。
*/
@Test
public void test(){
Set set = new HashSet();
set.add(123);
set.add(456);
set.add("fgd");
set.add("book");
set.add(new User("Tom",12));
set.add(new User("Tom",12));
set.add(129);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
1.3,HashSet中元素的添加过程
-
HashSet是Set 接口的典型实现,大多数时候使用Set 集合时都使用这个实现类。
-
HashSet按Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除性能。
-
HashSet具有以下特点:不能保证元素的排列顺序
- HashSet不是线程安全的
- 集合元素可以是null
-
底层也是数组,初始容量为16,当如果使用率超过0.75,(16*0.75=12)就会扩大容量为原来的2倍。(16扩容为32,依次为64,128…等)
-
HashSet 集合判断两个元素相等的标准:两个对象通过hashCode() 方法比较相等,并且两个对象的==equals()==方法返回值也相等。
-
对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
-
常用方法
- add(obj):添加元素,如果该元素已经存在,则add()仅返回false:
- contains(obj):判断元素obj是否已经存在
- remove(obj):删除元素obj
- isEmpty():判断集合是否为空
- clear():删除引用集中存在的所有值,从而使其成为空集。
/*
* Set:存储无序的,不可重复的数据
* 1.无序性: 不等于随机性,存储的数据在底层数组中并非按照数组索引的顺序添加。而是根据数据的hash值决定的
*
* 2.不可重复性:保证添加的元素按照equals方法判断时不能返回true,即相同的元素只能添加一个
*
* 添加数据的过程:以hashSet为例;
* 我们向HashSet中添加元素a,首先调用a所在类的hashCode()方法计算a的hash值,
* 此hash值介质通过某种算法计算出在HashSet底层数组中的存放位置,判断数组此位
* 置是否已经有其他元素:
* 如果没有其他元素,则a添加成功--->拉链法添加
* 如果有其他元素b或多个,则比较b或多个的hash值,如果hash值不相同,则元素添加成功,
* 如果hash值相同,则调用a的equals方法,equals返回true则添加失败否则添加成功
*
* 对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。
*
* jdk 7 :元素a放到数组中,指向原来的元素。
* jdk 8 :原来的元素在数组中,指向元素a
* 总结:七上八下
*/
1.4,关于hashCode()和equals()的重写
1.4.1,重写hashCode() 方法的基本原则
- 在程序运行时,同一个对象多次调用==hashCode()==方法应该返回相同的值。
- 当两个对象的equals()方法比较返回true时,这两个对象的==hashCode()==方法的返回值也应相等。
- 对象中用作equals() 方法比较的Field,都应该用来计算hashCode值。
1.4.2,重写equals() 方法的基本原则
- 当一个类有自己特有的“逻辑相等”概念,当改写equals的时候,总是要改写hashCode(),根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。
- 因此,违反了“相等的对象必须具有相等的散列码”。
- 结论:复写equals方法的时候一般都需要同时复写hashCode方法。通常参与计算hashCode的对象的属性也应该参与到equals()中进行计算
/**
* 2.要求:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()
* 要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
* 重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
*/
1.5,LinkedHashSet的使用
- LinkedHashSet是HashSet的子类
- LinkedHashSet根据元素的hashCode值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
- LinkedHashSet插入性能略低于HashSet,但在迭代访问Set 里的全部元素时有很好的性能。
- LinkedHashSet不允许集合元素重复。
//LinkedHashSet的使用
/*
* LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个
* 数据和后一个数据。
* 优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
* */
@Test
public void test2(){
Set set=new LinkedHashSet();
set.add(456);
set.add(123);
set.add(123);
set.add("AA");
set.add("BB");
set.add(new User("Tom",12));
set.add(new User("Tom",12));
set.add(129);
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
1.6,TreeSet
- TreeSet 是一个有序的集合,它的作用是提供有序的Set集合。
- TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
- TreeSet底层使用红黑树结构存储数据
- -TreeSet是有序的Set集合,因此支持add、remove、get等方法。
- 新增的方法如下:
- Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null;
- Object first():返回集合中的第一个元素;
- Object last():返回集合中的最后一个元素;
- Object lower(Object e):返回指定元素之前的元素。
- Object higher(Object e):返回指定元素之后的元素。
- SortedSet subSet(fromElement, toElement):返回此Set的子集合,含头不含尾
- SortedSet headSet(toElement):返回此Set的子集,由小于toElement的元素组成;
- SortedSet tailSet(fromElement):返回此Set的子集,由大于fromElement的元素组成;