1、Set接口
-
特点:
无序的:不保证元素的插入次序。
唯一:Set中存放的是对象的引用,所以相同的对象是没法添加到集合中,即集合中不允许有相同的元素对象。主要先根据hashcode值,如果相同再看是否重写了equals方法。
-
注意:
虽然Set中元素没有顺序,但是元素在set中的位置是由该元素的HashCode决定的,其具体位置其实是固定的。
2、常用实现类:
HashSet :
1、它不允许出现重复元素;不保证集合中元素的顺序
2、 允许包含值为null的元素,但最多只能有一个null元素。
3、 HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。
-
HashSet使用和理解中容易出现的误区:
a.HashSet中存放null值
HashSet中是允许存入null值的,但是在HashSet中仅仅能够存入一个null值。b.HashSet中存储元素的位置是固定的
HashSet中存储的元素的是无序的,这个没什么好说的,但是由于HashSet底层是基于Hash算法实现的,使用了hashcode,所以HashSet中相应的元素的位置是固定的。
TreeSet :
可以实现排序等功能的集合,它在讲对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,并保证该集合元素组成按照“升序”排列。
TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。
- 注意:
TreeSet集合不是通过hashcode和equals函数来比较元素的,而是通过实现Comparable接口并重写compareTo()方法或者Comparator接口的compare()来判断元素是否相等
- 小结:
a) 在对大量信息进行检索(不知道下标,比如contains)的时候,TreeSet比ArrayList更有效率。
b) TreeSet是用树形结构来存储信息的,每个节点都会保存一下指针对象,分别指向父节点,左分支,右分支,相比较而言,ArrayList就是一个含有元素的简单数组了,正因为如此,它占的内存也要比ArrayList多一些。
c) 想TreeSet插入元素也比ArrayList要快一些,因为当元素插入到ArrayList的任意位置时,平均每次要移动一半的列表(普遍的都是,set查询慢,插入快,list查询快,插入慢)。
3、示例代码
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestHashSet {
public static void main(String[] args) {
// HashSet的基本用法
// Set集合特点:
// 1、存储的元素是无序(不是添加的顺序),且唯一(不可重复)
// 创建Set集合对象
Set<String> carSet = new HashSet<>();
// 添加元素:add(Object obj)
System.out.println("------------------- 无序 -------------------");
carSet.add("Audi");
carSet.add("Benz");
carSet.add("Bmw");
carSet.add("Volvo");
System.out.println("carSet集合元素:" + carSet);
System.out.println("------------------- 唯一 -------------------");
carSet.add("Volvo");
System.out.println("carSet集合元素:" + carSet);
// 扩展:能不能存放null元素?可以,数量只有一个
System.out.println("------------------- null -------------------");
carSet.add(null);
carSet.add("Byd");
carSet.add(null);
System.out.println("carSet字符串集合元素:" + carSet);
// 获取元素:get(index),没有此方法,set集合是无序,元素没有下标,没有根据下标获取元素的方法
// carSet.get(0); // 编译不通过,没有此方法
// 获取元素个数:size() , 返回集合中元素个数
System.out.println("------------------- size -------------------");
System.out.println("carSet字符串集合元素个数:" + carSet.size());
// 判断是否包含某个元素:contains(Object obj),如果包含指定元素,返回true,否则返回false
System.out.println("------------------- contains -------------------");
System.out.println("carSet字符串集合是否包含Bmw?:" + carSet.contains("Bmw"));
// 其它的集合操作方法,比如判断非空,清空等,不一一介绍,课后自行测试
// 遍历集合中的元素:
// 方式1:使用迭代器
System.out.println("------------------- 迭代器遍历 -------------------");
Iterator<String> carIterator = carSet.iterator();
while (carIterator.hasNext()) {
System.out.println("carSet中的元素:" + carIterator.next());
}
// 方式2:增强for循环,普通for无法实现
System.out.println("------------------- 增强for遍历 -------------------");
for (String carStr : carSet) {
System.out.println("carSet中的元素:" + carStr);
}
// 探讨:Set集合中,存储的元素是唯一的,重复的元素如何保证唯一?是覆盖重复元素还是加不进去?
// 不是覆盖,先判断元素的hashCode值,如果相同,再判断equals是否相同,如果相同,不添加
// 创建SetUnique对象1
SetUnique setUnique1 = new SetUnique();
setUnique1.setSetScore(100);
// 创建SetUnique对象2
SetUnique setUnique2 = new SetUnique();
setUnique2.setSetScore(150);
System.out.println("------------------- -------------------");
System.out.println("== 判断 setUnique1和setUnique2是否是同一个对象?" + (setUnique1 == setUnique2));
System.out.println("equals 判断 setUnique1和setUnique2是否是同一个对象?" + (setUnique1.equals(setUnique2)));
// 创建set集合,添加元素
Set<SetUnique> setUniques = new HashSet<>();
setUniques.add(setUnique1);
setUniques.add(setUnique2);
System.out.println("setUniques中元素:" + setUniques);
}
}
/**
* Set唯一特性测试类
*
* @author xiayimiaoyijiuyonggan
*
*/
public class SetUnique {
private int setScore;
public int getSetScore() {
return setScore;
}
public void setSetScore(int setScore) {
this.setScore = setScore;
}
@Override
public int hashCode() {
// 重新hashCode
// 场景1:setScore值作为hashCode值,
// return this.setScore;
// 场景2:自定义一个逻辑,确保不同的setScore,返回相同的hashCode
return this.setScore / 100;
}
@Override
public boolean equals(Object obj) {
// 重写equals方法
// TODO 参数非空,类型判断(instanceOf)不做了
// 场景1:默认不管setScore是否相同,默认都是同一个对象,hashCode值不同,即便equals相同也是不同对象
return true;
// 场景2:自定义一个逻辑,根据setScore判断是否是同一个对象,如果setScore相同,就是同一个对象,不同就不是同一个对象
// hashCode值相同,会判断equals是否相同,如果相同就是同一个对象,如果不同就不是同一个对象
/*
* SetUnique setUnique = (SetUnique) obj; // 判断setScore值是否相同 if
* (this.setScore != setUnique.getSetScore()) { // 不是同一个对象 return false;
* }
*
* // 同一个对象 return true;
*/
}
@Override
public String toString() {
return "SetUnique [setScore=" + setScore + "]";
}
}