Java - 集合(二)
一、Collections
概述
• java.utils.Collections是集合工具类,用来对集合进行操作。
常用方法
• public static void shuffle (List<?> list) : 打乱集合顺序。
• public static void sort (List list): 将集合中元素按照默认规则排序。
比较器排序
用后面的跟前面的逐一进行比较,也就是左边放正要添加的元素,右边放集合中已有的,这样相减就是升序。
一般使用比较器都是只用一次,所以用匿名内部类就行
定义排序规则- 升序还是降序
//比较器,定义排序的规则,可以让集合按照升序获降序排列:Comparator-->int compare(T o1, T o2);
//o1代表后面的, o2代表则前面的
//o1 vs o2(例如:o1-o2) 结果是正数,o1要放到o2的后面 结果是0,顺序不变 结果是负数,o1要放到o2的前面
Comparator<Student> c = new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//s1代表正在添加的,s2代表已添加的
//升序s1 vs s2 正数,s1放到s2的后面 0不添加当前元素 负数s1放到s2的前面
//降序s2 vs s1
//优先级 优先按照哪个属性排序
//需求:优先按照姓名降序排序,(姓名相同)再按照年龄升序排序
int num = s2.name.compareTo(s1.name);
num = (num == 0) ? (s1.age - s2.age) : num;
return num;
}
};
可变参数
可变参数:数量较少时使用,本质上就是数组,固定数量的参数一定要放在可变参数前面
可变参数应用:Collections.addAll (集合,可变参数):把后面的所有元素全部加到前面的集合中
二、Set
- HashSet 存储自定义类型
HashMap - 默认用的是数组,同类数据用链表放一列,多个就用红黑树,兼具查询快,获取快的优点
数据结构是可以多个组合起来用的。
存放数据的流程
<1> 先给对象分配一个哈希值。
<2> 通过一个算式算出给他分配的位置,也就是索引。
<3> 放进去。
<4> 如果还有对象要加进来,也是先算出索引,如果位置一样,也就是代表哈希值一样。
<5> 再用equals 与上一个比较内容,如果内容相同,那就不放了,因为相同的元素只放一个,因为要遵循不能重复的规则;内容不同但哈希值相同,那就挂在上一个的下一个。
<6> 我们自己定义的类,都要重写 hashcode () 方法,因为new 出来的对象地址肯定是不同的,如果不重写的话,那么到时候equals 方法默认比较的是地址,那肯定不同,他就会存进去一个可能是重复的值,因为如果我创建了两个相同的对象,比如姓名和年龄一样,但是因为比较的是地址,那肯定不同,所以hashset就以为我们不同,就放进去了,那这是不行的,因为存储了两个相同内容的对象,这不是我们要的效果。
<7> 哈希值尽量不同比较好,因为可以分散开,如果都挂在一列,查询很慢。
<8> 到时候有定义了主键后,就只关注主键不同就行,equals 与 hashcode 方法中只判断 id 。
<9> 延迟加载的思想,先定义,里面没东西我先不加载,但是加载的大小也不能太大,不然到时候运行再加载,延迟加载的内容太大,那就又会等很久,体验不好。
- LinkedHashSet 存储自定义类型
与HashSet 不同的是,它存取有序,因为他到时候加元素的时候用的是双链表。
TreeSet 存储自定义类型
用的是红黑树,必须要指定排序规则,不然它不知道是升序还是降序。
自然排序:
@Override public int compareTo(Student s) {//this vs s this代表正在添加的, s代表已添加的 //升序this vs s 正数,this放到s的后面 0不添加当前元素 负数this放到s的前面 //降序s vs this //优先级 优先按照哪个属性排序 //需求:优先按照姓名升序排序,(姓名相同)再按照年龄降序排序 int num= this.name.compareTo(s.name); //判断如果num是0(姓名相同),再按照年龄降序排序 num= (num==0)?s.age-this.age:num; return num; }
比较器排序
//比较器排序:实现Comparator接口,重写比较规则。该实现类对象需要作为TreeSet构造方法参数。 //如果两种排序方式同时在,先走比较器。 Comparator<Student> c = new Comparator<Student>() { @Override public int compare(Student s1, Student s2) { //s1代表正在添加的,s2代表已添加的 //升序s1 vs s2 正数,s1放到s2的后面 0不添加当前元素 负数s1放到s2的前面 //降序s2 vs s1 //优先级 优先按照哪个属性排序 //需求:优先按照姓名降序排序,(姓名相同)再按照年龄升序排序 int num = s2.name.compareTo(s1.name); num = (num == 0) ? (s1.age - s2.age) : num; return num; } };
比较器排序优先于自然排序。
先看是不是Comparable的子类,如果是那就用他的compare(),不然的话会转换从成Comparator,然后用compareto()方法,如果你自己定义的类没有实现Comparable,那么就不是它的子类,所以他会报转换异常错误。
三、Map
Map概述
单列集合的底层是双列集合,集合相当于有一列为空
左边不允许重复,右边允许重复
Map集合通用方法
map.put( ),第一次添加的时候,返回的是null,因为他返回的是旧值,既是添加方法其实也是修改方法。
keySet() 方法中的 “Set” 单词指的是Set集合,不是设置的意思。
获取键值对方法的原理,Map.Entry<a,b>,是Set 中的一个内部接口。
键 找值遍历Map集合
键值对 对象 遍历Map集合
//创建集合对象
Map<Integer, String> map = new HashMap<>();
//添加数据
map.put(1, "刘备");
map.put(2, "关羽");
map.put(3, "张飞");
//遍历集合
//①获取所有的键值对对象
Set<Map.Entry<Integer, String>> entries = map.entrySet();
//②遍历键值对对象的集合,获取每个对象的键和值
for (Map.Entry<Integer, String> entry : entries) {
//获取键和值
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "===" + value);
}
HashMap 键列 存储自定义类型
LinkedHashMap键列存储自定义类型
TreeMap键列存储自定义类型 - 自带去重,不需要重新equals() 与hashcode() 方法