目录
1.Set集合
1.1set集合的特点
【1】无序:添加数据的顺序和获取出的数据顺序不一致; 不重复; 无索引。
【2】Set要用到的常用方法,基本上都是Collection提供 。
1.2Set集合的常见实现类及特点
【1】HashSet : 无序、不重复、无索引。
【2】LinkedHashSet:有序、不重复、无索引。
【3】TreeSet:排序、不重复、无索引。
1.3HashSet集合
1.3.1HashSet集合的特点
无序、不重复、无索引
public static void main(String[] args) {
// 目标:认识Set家族集合的特点。
// 1、创建一个Set集合,特点:无序,不重复,无索引。
set.add("鸿蒙");
set.add("鸿蒙");
set.add("java");
set.add("java");
set.add("电商设计");
set.add("电商设计");
set.add("新媒体");
set.add("大数据");
System.out.println(set);
}
1.3.2哈希值
【1】哈希值就是一个int类型的随机值,Java中每个对象都有一个哈希值。
【2】Java中的所有对象,都可以调用Obejct类提供的hashCode方法,返回该对象自己的哈希值。
public int hashCode() //返回对象的哈希码值
1.3.3对象哈希值的特点
【1】同一个对象多次调用hashCode()方法返回的哈希值是相同的。
【2】不同的对象,它们的哈希值大概率不相等,但也有可能会相等(哈希碰撞)。
【3】存储于哈希表内。
1.3.4哈希表
【1】JDK8之前,哈希表 = 数组+链表
【2】JDK8开始,哈希表 = 数组+链表+红黑树
【3】哈希表是一种增删改查数据,性能都较好的数据结构 。
1.3.5红黑树
【1】红黑树,就是可以自平衡的二叉树
【2】红黑树是一种增删改查数据性能相对都较好的结构。
1.3.6哈希表存储数据的详细流程
【1】创建一个默认长度16,默认加载因子为0.75的数组,数组名table
【2】根据元素的哈希值跟数组的长度计算出应存入的位置
【3】判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组。
【4】当数组存满到16*0.75=12时,就自动扩容,每次扩容成原先的两倍
1.3.7HashSet集合去重复的机制
public static void main(String[] args) {
// 目标:掌握HashSet集合去重操作。
Student s1 = new Student("张三", 18, "北京", "123456");
Student s2 = new Student("李四", 19, "上海", "989876");
Student s3 = new Student("张三", 18, "北京", "123456");
Student s4 = new Student("李四", 19, "上海", "989876");
Set<Student> set = new HashSet<>(); // 不重复的!
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
System.out.println(set);
}
1.4LinkedHashSet集合
1.4.1LinkedHashSet集合的特点
有序、不重复、无索引
public static void main(String[] args) {
// 目标:认识Set家族集合的特点。
// 1、创建一个Set集合,特点:无序,不重复,无索引。
Set<String> set = new LinkedHashSet<>(); // LinkedHashSet 有序,不重复,无索引。
set.add("鸿蒙");
set.add("鸿蒙");
set.add("java");
set.add("java");
set.add("电商设计");
set.add("电商设计");
set.add("新媒体");
set.add("大数据");
System.out.println(set);
}
1.4.2LinkedHashSetde底层原理
【1】依然是基于哈希表(数组、链表、红黑树)实现的。
【2】它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
1.5TreeSet集合
1.5.1TreeSet集合的特点
【1】不重复、无索引、可排序(默认升序排序 ,按照元素的大小,由小到大排序)。
【2】底层是基于红黑树实现的排序。
public static void main(String[] args) {
// 目标:认识Set家族集合的特点。
// 1、创建一个TreeSet集合:排序(默认一定要大小升序排序),不重复,无索引。
Set<Double> set1 = new TreeSet<>();
set1.add(3.14);
set1.add(5.6);
set1.add(1.0);
set1.add(1.0);
set1.add(2.0);
System.out.println(set1);
}
1.5.2排序时的特点
【1】对于数值类型:Integer , Double,默认按照数值本身的大小进行升序排序。
【2】对于字符串类型:默认按照首字符的编号升序排序。
【3】对于自定义类型如Student对象,TreeSet默认是无法直接排序的,因为不知道大小规则。
1.5.3自定义排序规则
【1】方式一:让自定义的类(如老师类)实现Comparable接口,重写里面的compareTo方法来指定比较规则。
【2】方式二:通过调用TreeSet集合有参数构造器,可以设置Comparator对象(比较器对象,用于指定比较规则。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher implements Comparable<Teacher>{
private String name;
private int age;
private double salary;
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}' + "\n";
}
// t2.compareTo(t1)
// t2 == this 比较者
// t1 == o 被比较者
// 规定1:如果你认为左边大于右边 请返回正整数
// 规定2:如果你认为左边小于右边 请返回负整数
// 规定3:如果你认为左边等于右边 请返回0
// 默认就会升序。
@Override
public int compareTo(Teacher o) {
// 按照年龄升序
// if(this.getAge() > o.getAge()) return 1;
// if(this.getAge() < o.getAge()) return -1;
// return 0;
return this.getAge() - o.getAge(); // 升序
// return o.getAge() - this.getAge(); // 降序
}
public static void main(String[] args) {
// 目标:搞清楚TreeSet集合对于自定义对象的排序
Set<Teacher> teachers = new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
// return o2.getAge() - o1.getAge(); //降序
// if(o1.getSalary() > o2.getSalary()){
// return 1;
// }else if(o1.getSalary() < o2.getSalary()){
// return -1;
// }
// return 0;
// return Double.compare(o1.getSalary(), o2.getSalary()); // 薪水升序
return Double.compare(o2.getSalary(), o1.getSalary()); // 薪水升序
}
}); // 排序,不重复,无索引
// 简化形式
// Set<Teacher> teachers = new TreeSet<>((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary())); // 排序,不重复,无索引
teachers.add(new Teacher("老陈", 20, 6232.4));
teachers.add(new Teacher("dlei", 18, 3999.5));
teachers.add(new Teacher("老王", 22, 9999.9));
teachers.add(new Teacher("老李", 20, 1999.9));
System.out.println(teachers);
// 结论:TreeSet集合默认不能 给自定义对象排序啊,因为不知道大小规则。
// 一定要能解决怎么办?两种方案。
// 1、对象类实现一个Comparable比较接口,重写compareTo方法,指定大小比较规则
// 2、public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则
}
1.5.4排序时返回值的规则
【1】如果认为第一个元素 > 第二个元素 返回正整数即可。
【2】如果认为第一个元素 < 第二个元素返回负整数即可。
【3】如果认为第一个元素 = 第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。
【4】如果类本身有实现Comparable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。
2.Map集合
2.1Map集合的特点
【1】Map集合也被叫做“键值对集合”,格式:{key1=value1 , key2=value2 , key3=value3 , ...}
【2】Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值
【3】Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的
2.2Map集合的应用场景
需要存储一一对应的数据时,就可以考虑使用Map集合来做
2.3Map集合的常见实现类及特点
【1】HashMap: 无序、不重复、无索引; (用的最多)
【2】LinkedHashMap :有序、不重复、无索引。
【3】TreeMap :按照大小默认升序排序、不重复、无索引。
2.4Map集合的常用方法
Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的。
方法名称 | 说明 |
public V put(K key,V value) | 添加元素 |
public int size() | 获取集合的大小 |
public void clear() | 清空集合 |
public boolean isEmpty() | 判断集合是否为空,为空返回true , 反之 |
public V get(Object key) | 根据键获取对应值 |
public V remove(Object key) | 根据键删除整个元素 |
public boolean containsKey(Object key) | 判断是否包含某个键 |
public boolean containsValue(Object value) | 判断是否包含某个值 |
public Set<K> keySet() | 获取全部键的集合 |
public Collection<V> values() | 获取Map集合的全部值 |
public static void main(String[] args) {
// 目标:掌握Map的常用方法。
Map<String,Integer> map = new HashMap<>();
map.put("嫦娥", 20);
map.put("女儿国王", 31);
map.put("嫦娥", 28);
map.put("铁扇公主", 38);
map.put("紫霞", 31);
map.put(null, null);
System.out.println(map); // {null=null, 嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
// 写代码演示常用方法
System.out.println(map.get("嫦娥")); // 根据键取值 28
System.out.println(map.get("嫦娥2")); // 根据键取值 null
System.out.println(map.containsKey("嫦娥")); // 判断是否包含某个键 true
System.out.println(map.containsKey("嫦娥2")); // false
System.out.println(map.containsValue(28)); // 判断是否包含某个值 true
System.out.println(map.containsValue(28.0)); // false
System.out.println(map.remove("嫦娥")); // 根据键删除键值对,返回值
System.out.println(map);
// map.clear(); // 清空map
// System.out.println(map);
System.out.println(map.isEmpty()); // 判断是否为空
System.out.println(map.size()); // 获取键值对的个数 4
// 获取所有的键放到一个Set集合返回给我们
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key);
}
// 获取所有的值放到一个Collection集合返回给我们
Collection<Integer> values = map.values();
for (Integer value : values) {
System.out.println(value);
}
}
2.5Map集合的遍历方式
2.5.1键找值
先获取Map集合全部的键,再通过遍历键来找值。
public static void main(String[] args) {
// 目标:掌握Map集合的遍历方式一:键找值。
Map<String,Integer> map = new HashMap<>();
map.put("嫦娥", 20);
map.put("女儿国王", 31);
map.put("嫦娥", 28);
map.put("铁扇公主", 38);
map.put("紫霞", 31);
System.out.println(map); // {嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
// 1、提起Map集合的全部键到一个Set集合中去
Set<String> keys = map.keySet();
// 2、遍历Set集合,得到每一个键
for (String key : keys) {
// 3、根据键去找值
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
}
2.5.2键值对
把“键值对“看成一个整体进行遍历(难度较大)
public static void main(String[] args) {
// 目标:掌握Map集合的遍历方式二:键值对。
Map<String,Integer> map = new HashMap<>();
map.put("嫦娥", 20);
map.put("女儿国王", 31);
map.put("嫦娥", 28);
map.put("铁扇公主", 38);
map.put("紫霞", 31);
System.out.println(map); // {嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
// 1、把Map集合转换成Set集合,里面的元素类型都是键值对类型(Map.Entry<String, Integer>)
/**
* map = {嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
* ↓
* map.entrySet()
* ↓
* Set<Map.Entry<String, Integer>> entries = [(嫦娥=28), (铁扇公主=38), (紫霞=31), (女儿国王=31)]
* entry
*/
Set<Map.Entry<String, Integer>> entries = map.entrySet();
// 2、遍历Set集合,得到每一个键值对类型元素
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}
}
2.5.3Lambda
JDK 1.8开始之后的新技术(非常的简单)
public static void main(String[] args) {
// 目标:掌握Map集合的遍历方式三:Lambda。
Map<String,Integer> map = new HashMap<>();
map.put("嫦娥", 20);
map.put("女儿国王", 31);
map.put("嫦娥", 28);
map.put("铁扇公主", 38);
map.put("紫霞", 31);
System.out.println(map); // {嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
// 1、直接调用Map集合的forEach方法完成遍历
// map.forEach(new BiConsumer<String, Integer>() {
// @Override
// public void accept(String key, Integer value) {
// System.out.println(key + "=" + value);
// }
// });
map.forEach((k,v) -> System.out.println(k + "=" + v));
}
2.6HashMap集合
2.6.1HashMap集合的特点
无序、不重复、无索引; (用的最多)
public static void main(String[] args) {
// 目标:认识Map集合的体系特点。
// 1、创建Map集合
// Map特点/HashMap特点:无序,不重复,无索引,键值对都可以是null, 值不做要求(可以重复)
// LinkedMap特点:有序,不重复,无索引,键值对都可以是null, 值不做要求(可以重复)
// TreeMap: 按照键可排序,不重复,无索引
Map<String,Integer> map = new HashMap<>(); // 一行经典代码
// Map<String,Integer> map = new LinkedHashMap<>();
map.put("嫦娥", 20);
map.put("女儿国王", 31);
map.put("嫦娥", 28);
map.put("铁扇公主", 38);
map.put("紫霞", 31);
map.put(null, null);
System.out.println(map); // {null=null, 嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
}
2.6.2HashMap底层原理
HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的。上面学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。
2.7LinkedHashMap集合
2.7.1LinkHashMap集合的特点
有序、不重复、无索引。
public static void main(String[] args) {
// 目标:认识Map集合的体系特点。
// 1、创建Map集合
// Map特点/HashMap特点:无序,不重复,无索引,键值对都可以是null, 值不做要求(可以重复)
// LinkedMap特点:有序,不重复,无索引,键值对都可以是null, 值不做要求(可以重复)
// TreeMap: 按照键可排序,不重复,无索引
// Map<String,Integer> map = new HashMap<>(); // 一行经典代码
Map<String,Integer> map = new LinkedHashMap<>();
map.put("嫦娥", 20);
map.put("女儿国王", 31);
map.put("嫦娥", 28);
map.put("铁扇公主", 38);
map.put("紫霞", 31);
map.put(null, null);
System.out.println(map); // {null=null, 嫦娥=28, 铁扇公主=38, 紫霞=31, 女儿国王=31}
}
2.7.2LinkHashMap集合底层原理
底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。上面学习的LinkedHashSet集合的底层原理就是LinkedHashMap。
2.8TreeMap集合
2.8.1 TreeMap集合的特点
不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)
2.8.2 TreeMap集合底层原理
TreeMap跟TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。
2.8.3排序规则
【1】让类实现Comparable接口,重写比较规则。
【2】TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。