Set集合
Set接口是Collection的子接口,set接口没有提供额外的方法。但是比Collection
接口更加严格了。
Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
Set集合支持的遍历方式和Collection集合一样:foreach和Iterator。
Set的常用实现类有:HashSet、TreeSet、LinkedHashSet。
1 、HashSet
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
java.util.HashSet
底层的实现其实是一个java.util.HashMap
支持,然后HashMap的底层物理实现是一个Hash表。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。
import java.util.Objects;
public class MyDate {
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyDate myDate = (MyDate) o;
return year == myDate.year &&
month == myDate.month &&
day == myDate.day;
}
@Override
public int hashCode() {
return Objects.hash(year, month, day);
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}
import org.junit.Test;
import java.util.HashSet;
public class TestHashSet {
@Test
public void test01(){
HashSet<String> set = new HashSet<>();
set.add("张三");
set.add("张三");
set.add("李四");
set.add("王五");
set.add("王五");
set.add("赵六");
System.out.println("set = " + set);//不允许重复,无序
}
@Test
public void test02(){
HashSet<MyDate> set = new HashSet<>();
set.add(new MyDate(2021,1,1));
set.add(new MyDate(2021,1,1));
set.add(new MyDate(2022,2,4));
set.add(new MyDate(2022,2,4));
System.out.println("set = " + set);//不允许重复,无序
}
}
2、LinkedHashSet
LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。java.util.LinkedHashSet
,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
import org.junit.Test;
import java.util.LinkedHashSet;
public class TestLinkedHashSet {
@Test
public void test01(){
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("张三");
set.add("张三");
set.add("李四");
set.add("王五");
set.add("王五");
set.add("赵六");
System.out.println("set = " + set);//不允许重复,体现添加顺序
}
}
3、TreeSet
TreeSet里面维护了一个TreeMap,底层是基于红黑树实现的!
TreeSet特点:
- 不允许重复
- 实现排序:自然排序或定制排序
如何实现去重的?
如果使用的是自然排序,则通过调用实现的compareTo方法
如果使用的是定制排序,则通过调用比较器的compare方法
如何排序?
方式一:自然排序
让待添加的元素类型实现Comparable接口,并重写compareTo方法
方式二:定制排序
创建Set对象时,指定Comparator比较器接口,并实现compare方法
示例代码:
import org.junit.Test;
import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
import java.util.TreeSet;
public class TestTreeSet {
@Test
public void test01(){
TreeSet<String> set = new TreeSet<>();
set.add("张三");
set.add("张三");
set.add("张飞");
set.add("李四");
set.add("王五");
set.add("王五");
set.add("赵六");
System.out.println("set = " + set);
//不允许重复,体现大小顺序,String对象自然排序是依据Unicode编码值大小
for (String s : set) {
char[] chars = s.toCharArray();
int[] codes = new int[chars.length];
for (int i = 0; i < codes.length; i++) {
codes[i] = chars[i];
}
System.out.println(s + ":" + Arrays.toString(codes));
}
}
@Test
public void test02(){
//Collator.getInstance(Locale.CHINA)是Comparator接口的实现类对象
//String对象将按照字典顺序排列
TreeSet<String> set = new TreeSet<>(Collator.getInstance(Locale.CHINA));
set.add("张三");
set.add("张三");
set.add("张飞");
set.add("李四");
set.add("王五");
set.add("王五");
set.add("赵六");
System.out.println("set = " + set);
//不允许重复,体现大小顺序
}
}
小结:Set集合的方法与List那些方法大致相同使用,同样是有add,remover这些方法,但是Set集合他会将空元素填满,不会造成浪费,但排序的方法却是无序的。而LinkedHashSet对象则是Set的子类,且该方法会进行一个排序,有排序的固定方法。TreeSet 这个方法与Set方法一样是去重的同样他也有自己的排序。
Collections工具类
参考操作数组的工具类:Arrays。
Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:
- public static boolean addAll(Collection<? super T> c,T… elements)将所有指定元素添加到指定 collection 中。
- public static int binarySearch(List<? extends Comparable<? super T>> list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
- public static int binarySearch(List<? extends T> list,T key,Comparator<? super T> c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。
- public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
- public static T max(Collection<? extends T> coll,Comparator<? super T> comp)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
- public static void reverse(List<?> list)反转指定列表List中元素的顺序。
- public static void shuffle(List<?> list) List 集合元素进行随机排序,类似洗牌
- public static <T extends Comparable<? super T>> void sort(List list)根据元素的自然顺序对指定 List 集合元素按升序排序
- public static void sort(List list,Comparator<? super T> c)根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- public static void swap(List<?> list,int i,int j)将指定 list 集合中的 i 处元素和 j 处元素进行交换
- public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出现次数
- public static void copy(List<? super T> dest,List<? extends T> src)将src中的内容复制到dest中
- public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值
- Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
- Collections类中提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx的不可修改的视图。
小结:该工具类与Arrays差不多,值得注意的是该方法有个addAll方法,该方法可以直接加入若干元素。
总结:Set方法与TreeSet都可以达到一个去重的方法,该方法主要是靠计算机转换为2进制进行一个地址比较还有equals方法进行比较。
每日金句:
花开不是为了花落,而是为了灿烂。