一. ArrayList嵌套
1.定义
在集合中存放集合,和二维数组类似
2.演示
public static void main(String[] args) {
//集合中的元素还是集合
ArrayList
ArrayList
clas1.add(new Student("小红",18));
clas1.add(new Student("小明",20));
school.add(clas1);
ArrayList
clas2.add(new Student("小张",18));
clas2.add(new Student("小李",20));
school.add(clas2);
ArrayList
clas3.add(new Student("tom",18));
clas3.add(new Student("jack",20));
school.add(clas3);
System.out.println(school);
}
二. Set集合
1.定义
Set词义:数学中集合的概念。也是Collection的子接口。
Set作为Collection集合的子接口,没有新增的功能。但是有自己的存储特点。
Set集合存数的元素是无序的, 而且不允许储存重复的元素, 每当有新的元素存入的时候,Set集合会先去过滤, 如果发现和集合中现有元素出现重复, 就不在允许添加
2.应用场景
当我们不想让集合中出现重复的元素时,使用Set集合
当我们需要排除重复数据时,使用Set集合
3.演示
public static void main(String[] args) {
//集合中的元素还是集合
HashSet
Student student = new Student("小红",18);
Student student2 = new Student("小红",18);
s.add(student);
s.add(student2);
Iterator
while(it.hasNext()) {
Student student3=it.next();
System.out.println(student3);
}
}
三. HashSet
1.定义
Set接口的一个具体的实现类。
底层是由哈希表实现。它不保证迭代的顺序。特别是不保证顺序一直不变。
HashSet集合中的元素是通过hash值来比较是否相同
集合通过元素的hashCode和equals方法来比较两个元素是否相同, 不同就存入, 相同不存入
元素存入的位置未知,和存入的顺序无关
2.存储原理
HashSet最后还是存入数组中, 只是根据元素的Hash值来确定存入的角标位置
元素的hash值 ^ (元素的hash值 >>> 16) & (数组的长度-1)
HashSet中不是直接存入我们给定的元素, 而是用集合中的一个内部类封装我们存入的元素,所以当我们存入null的时候,不会因为和数组中角标位上默认值null起冲突
如果两个不同的元素根据不同的Hash值计算出了同一个角标值,那么都能存进去
3.构造方法
HashSet() 构造出一个新的集合, 底层数组默认的初始容量是16(扩容一倍),加载因子是0.75
加载因子: 集合中的数组可用的
角标值得可选范围越小,计算出重复角标值得概率就越高
HashSet(Collection extends E> c) 构造一个包含指定collection中元素的新set
4.常用方法
boolean add( E e) 如果此set集合中尚未包含指定元素,则添加指定元素
boolean remove(Object o) 移除某个元素 []
int size() 获取集合的长度
5.重点重点重点!!!HashSet集合去重的流程:
step1:先获取对象的hashCode,对象的哈希值不同,直接存储到HashSet容器中。
step2:如果哈希值相同,调用equals()比较。
true:认为是相同的元素,不存储
false:不同的元素,存储
原则:hashCode()和equals()的原则:
重写hashCode()的规则:自己生成hashCode值。公式
对象相同:属性值相同。那么哈希码必须相同。
对象不同:属性值不同。哈希码也可能相同。
重写equals()的原则:"权威的"
如果两个对象的属性值相同,认为是相同的对象,返回true。
如果两个对象的属性值有不同,就不是相同的对象,返回false。
结论:如果想使用HashSet集合,那么必须同时重写对象的hashCode()和equals()这两个方法。
重写的规则:
hashCode()
对象相同,属性值相同。哈希码必须相同。
对象不同,属性值不同。哈希码可能相同。
equals()
对象相同:属性值相同。必须true。
对象不同:属性值不同。必须false。
6.演示
需求: 去除ArrayList集合中的重复元素
public static void main(String[] args) {
ArrayList
al.add("a");
al.add("s");
al.add("x");
al.add("a");
al.add("s");
HashSet
System.out.println(hs);
}
7.测试题
需求: 创建Student类, 定义name和age属性, 创建多个对象(有属性重复的对象)存入ArrayList集合中, 然后对集合中的元素去重
四. HashSet集合中元素保证唯一性
1.原理解析
HashMap是通过调用元素的hashCode方法来比较两个元素是否形同的,所有如果要保证引用数据类型逻辑上的唯一性,就必须重写hashCode方法和equals方法
2.演示
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
prime = 31 的原因
别人选的, 没有原因
是质数, 和别的值计算得出的数重复的概率低
大小适中, 不会出现太大导致结果无法使用的问题
便于计算 2<<5 -1
3.引用数据类型除重
重写hashCode和equals方法,自定义比较内容
4.测试题
需求: 编写程序, 获取10个1到20的随机数, 要求随机数不能重复, 打印结果
public static void main(String[] args) {
Random random = new Random();
HashSet
while(hashSet.size()<10){
int num = random.nextInt(20)+1;
hashSet.add(num);
}
System.out.println(hashSet);
}
5.测试题
需求: 从键盘录入一行数据, 去掉其中重复的字符,打印结果
6.测试题
产生10个随机的字符串, 要求不能重复(字符串中的字符取值在 'a' 到 'z' , 'A' 到 'Z' ,'0' 到 '9'),字符串的长度1-20
五. LinkedHashSet
1.定义
兼顾了linked的有序性和HashSet的元素唯一性
2.演示
六. TreeSet集合
1.定义
TreeSet是一种顺序的集合, 记住, 这里的顺序是指集合中的元素有顺序, 她是通过比较元素的大小来存放的, 大的存右边,小的存左边
默认的规则:Comparable接口,定义排序的规则。
存入的元素必须实现Comparable接口,并且重写comparTo方法(注:重写的方法应在该元素的类中,而不是测试类中重写)
java.lang.Comparable接口的用途:强行对实现类的对象进行排序。
compareTo()-->此方法用于排序,返回值int类型
o1.compareTo(o2)-->int
正数:o1 > o2,将o1排在o2的后面。
负数:o1 < o2,将o1排在o2的前面。
零:认为o1和o2相同,不存储了。
最后存入的元素会形成一个树状结构
扩展内容:
红黑树--->平衡二叉树--->二叉树--->树
想了解平衡二叉树,可以参照此网址:https://baijiahao.baidu.com/s?id=1651427207567199156&wfr=spider&for=pc
2.构造方法
TreeSet() 构造一个新的空set, 该set根据其元素的自然顺序进行排序
TreeSet(Comparator super E> comparator) 构建一个空的TreeSet, 他根据指定比较器进行排序
3.常用方法
add(E e) 将指定元素添加到此set
first() 返回此set中当前第一元素
last() 返回此set中当前最后一个元素
floor() 返回此set中小于等于给定元素的最大元素,不存在则返回null
higher() 返回此set中严格大于给定元素的最小元素,不存在则返回null
5.添加原理
TreeSet会将第一个添加的元素作为中点, 以后添加的元素会先跟中点进行比较, 如果大于就接着跟所比较元素的右边的元素接着比较,如果小于就接着跟所比较元素左边的元素接着比较, 直到无法找到可比较的元素,就会将新添加的这个元素放到当前位置
6.Comparable接口(默认的比较器)
java.lang.Comparable接口
java.lang.Comparable接口的用途:强行对实现类的对象进行排序。
仅有唯一的一个方法:compareTo()-->此方法用于排序,返回值int类型类型
o1.compareTo(o2)-->int (从小到大排序)
正数:o1 > o2,将o1排在o2的后面。
负数:o1 < o2,将o1排在o2的前面。
零:认为o1和o2相同,不存储了。
默认的TreeSet集合,使用的是Comparable接口,来给对象进行排序。以及去重。
所有存入的元素在比较的时候,如果集合没有比较器, 就会将元素本身转成Comparator类型并调用comparTo方法进行比较, 所以我们必须实现Comparato接口,并重写comparTo方法
7.Comparator比较器(自定义的比较器)
这是一个接口, 定义了一个compare抽象方法
compare方法可以对两个元素进行比较
如果方法返回一个小于0的数,表示参数1小于参数2
如果返回 0 ,表示参数1等于参数2
如果返回一个大于0的数, 表示参数1大于参数2
演示
8.注意事项
TreeSet集合的存储原理限定了必须要对存入的元素进行比较
要么存入的元素自身实现Comparable接口, 要么提供外部的实现了Comparator接口的比较器, 否则程序运行就会报错
注意点:创建一个TreeSet集合,到底使用哪个比较器?Comparable?Comparator?
无参构造:new TreeSet();-->使用默认的比较器:Comparable
有参构造:new TreeSet(Comparator)-->使用自定义的比较器:Comparator
9.测试题
需求: 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
演示
10.LinkedHashSet集合
回忆:HashSet存储特点?1、无序。2、去重
HashSet存储数据,记录存储的顺序。
Set集合的另一个实现类:LinkedHashSet
存储原理同HashSet相同,但是外层套了一个链表结构。用于记录存储的顺序。
七. 超级for
1.定义
Iterator的简写形式
简化数组和Collection集合的遍历
2.格式
3.演示
4.三种迭代方式的删除
普通for循环,可以删除,但是需要角标
迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
超级for循环不能删除
八. Collections工具类的使用
1.定义
一个用于操作Collection集合工具类
2.常用方法
sort(List
swap(List
reverse(List> list ) 反转集合中的元素的顺序
replaceAll(List
3.演示
总结
1.Set集合:特点,去重,无序。
2.HashSet:
去重效率高, 尤其是在大数据量下,散列存储。不讲究存储顺序。
调用元素的hashCode和equals方法来比较是否相同
3.TreeSet:
去重, 元素有序(对存入的元素进行排序)
要求存入的元素必须具备比较的能力或者提供第三方的比较器
元素具备比较的能力 : 元素实现comperable接口, 重写comparTo方法
第三方比较器: 定义类,实现Compartor接口, 从写 compare方法
4.LinkedHashSet
即有序(集合有序), 又能去重
效率不高
5.超级for
迭代器的简写形式
优点: 格式简单
缺点: 无法进行删除操作
6.Collections
一个用来操作List集合的工具类