HashSet
特征:
- 底层实现是HashMap的key
- 默认初始化的容量是16,默认的加载因子是0.75
- 当存储容量达到原容量的0.75时,扩容为原容量的2倍
- 不保证顺序、唯一、可以为null、无索引
- 查找较慢、插入删除较快
- 线程不同步的,多线程使用不安全,实现同步Set set = Collections.synchronizedSet(new HashSet(…))
常用的方法:
add(E e)(要增加的元素)
size()//获取集合的长度
remove(Object o)(想要删除的元素)
clear()//清空
isEmpty()//判断是否为空
contains(Object o)(判断包含的元素)
iterator()//irerator遍历器
注意事项:
- HashSet按照按照什么逻辑排序
不保证顺序,存入的顺序和实际元素排列顺序无关,获取元素的先后顺序由Map中的hash()方法得到的混淆后的hash值决定。
- HashSet扩容是否有上限
HashMap限定了最大容量:MAXIMUM_CAPACITY = 1 << 30;
基本的创建以及赋值:
@Test
public void test1() {
HashSet<String> set1 = new HashSet<>();
set1.add("王子玉");
set1.add("吴青山");
set1.add("钟雪");
set1.add("任玉文");
System.out.println(set1);
}
遍历:
//迭代器遍历
Iterator<Integer> it = set2.iterator();
while (it.hasNext()) {
Integer i = (Integer) it.next();
System.out.println(i);
}
//foreach遍历
for (Integer i : set2) {
System.out.println(i);
}
排序的依据:
@Test
public void test3() {
String key1 = "tom";
int h1;
//根据获得的值进行排序
int i1 = (h1 = key1.hashCode()) ^ (h1 >>> 16);
System.out.println(i1);
String key2 = "hello";
int h2;
int i2 = (h2 = key2.hashCode()) ^ (h2 >>> 16);
System.out.println(i2);
}
LinkedHashSet
特征:
- 继承了HashSet类,底层实现HashMap,数据结构式链表
- 保证顺序、唯一的、可以为null
- 查找较慢、插入删除较快
- 线程不同步、多线程使用不安全,如果要实现线程同步的set
- Set set = Collections.synchroizedSet(new LinkedHashSet());
常用方法:
- 可以参考HashSet
基本的创建语句和赋值:
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("吴青山");
set.add("吴青山");
set.add("王子玉");
set.add("任玉文");
set.add(null);
System.out.println(set);
System.out.println(set.remove("吴青山"));
System.out.println(set);
}
TreeSet
特征:
- 底层实现是TreeMap,数据结构是二叉树
- 不保证排序,但是可以自定义排序、唯一、可以为null
- 线程不同步、多线程使用不安全,如果要实现同步的set
- Sorted set = Collection.synchroizedSortedSet(new TreeSet(…))
- TreeSet集合只能存处可排序的对象(如果对象不可排序,会报错。)
- 如何实现排序
让元素具有排序的功能
元素类实现Comparable接口,重写comparTo方法
1. 在元素被添加进容器时,会调用compareTo方发和已存在的元素进行比较
2. 如果返回的int值是正数,这个元素排在被比较的元素后面
3. 如果返回的int值是负数,这个元素排在被比较的元素前面
4. 如果返回的int值是0,表示无法比较,这个元素无法添加进容器里面
让容器具有排序的功能
1. 创建一个比较器的类,实现Comparator,重写compara方法
2. 使用有参构造创建TreeSet,参数就是比较器类的对象
创建和赋值:
@Test
public void test1() {
TreeSet<String> set = new TreeSet<>();
set.add("王子玉");
set.add("韩文龙");
set.add("任玉文");
System.out.println(set);
}
创建有序的对象:
/**
* 学生对象
*/
//实现Comparable接口
public class Student implements Comparable<Student> {
private String name;
private int age;
private char sex;
public Student() {
super();
}
public Student(String name, int age, char sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
//重写comparaTo方法,如果不重写,会报ClassCastException异常
@Override
public int compareTo(Student student) {
if (this.sex != student.sex) {
return this.sex == '女' ? -1 : 1;
} else {
return student.age - this.age;
}
}
}
由于业务场景设定我们需要创建不同的排序规则,所以使用容器实现更加合理
实现容器有序:
/**
* 教师类比较器
*/
//实现Comparator接口
public class TeacherComparator implements Comparator<Teacher> {
//重写比较方法
@Override
public int compare(Teacher t1, Teacher t2) {
return t2.getAge() - t1.getAge();
}
}
@Test
public void test3() {
//创建比较器对象
TeacherComparator tc = new TeacherComparator();
//将比较器对象放入TreeSet对象的构造方法中
TreeSet<Teacher> set = new TreeSet<>(tc);
set.add(new Teacher("郭老师", 20, '女'));
set.add(new Teacher("吴老师", 40, '男'));
set.add(new Teacher("方老师", 16, '男'));
System.out.println(set);
}
由于Comparator接口是函数式的接口,所以可以用函数式的编程,不用额外创建一个比较器的类了
//函数式的编程
TreeSet<Girlfriend> set = new TreeSet<>((g1, g2) -> {
if (g1.getFaceValue() != g2.getFaceValue()) {
return g2.getFaceValue() - g1.getFaceValue();
} else if (g1.getAge() != g2.getAge()) {
return g1.getAge() - g2.getAge();
} else {
return 1;
}
});