11.10 Set
**Set :**无序,不可重复,去重
- **无序:**存放的顺序与内部真实存储的顺序不一致
- **去重:**集合不包含元素对e1和e2 ,使得e1.equals(e2)和最多一个null元素
- **新增功能:**static Set of(E… elements) 返回包含任意数量元素的不可修改集
- 遍历方式:
- foreach
- iterator迭代器
11.11 TreeSet
TreeSet :
- 底层结构 : 红黑树
- **特点 :**查询效率较高,自动把数据做升序排序
- 底层是由TreeMap维护的
- **新增功能:**新增了一些与比较大小相关的方法
- 遍历方式 :
- foreach
- iterator迭代器
- 注意 :
TreeSet需要存储相同类型的数据,因为会默认存在比较排序
11.12 内部比较器
TreeSet存储javabean类型的数据
**去重与排序:**都是根据比较规则实现的,与equals没有关系
比较规则:
- 内部比较器|内部比较规则|自然排序 : 比较规则定义在javabean类型的内部
- javabean类型实现Comparable接口,重写compareTo(T o)方法,在方法中定义比较规则
package Tuesday;
import java.util.TreeSet;
public class TreeSet2 {
public static void main(String[] args) {
TreeSet<Teacher> sc=new TreeSet<>();
sc.add(new Teacher(01,"wang",10000));
sc.add(new Teacher(04,"chang",23000));
sc.add(new Teacher(03,"zhao",16000));
System.out.println(sc);
}
}
package Tuesday;
public class Teacher implements Comparable<Teacher> {
private int id;
private String name;
private int sal;
public Teacher() {
}
public Teacher(int id, String name, int sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSal() {
return sal;
}
public void setSal(int sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", sal=" + sal +
'}';
}
@Override
public int compareTo(Teacher o) {
return this.sal-o.sal;
//return this.name.compareTo(o.name);
}
}
11.13 外部比较器
外部比较器|外部比较规则|定制排序 : 比较规则定义在javabean类型的外部
定义一个实现类,实现Comparator接口,重写int compare(T o1, T o2),在方法中定义比较规则
package Tuesday;
import java.util.Comparator;
import java.util.TreeSet;
public class Test1 {
public static void main(String[] args) {
// 匿名内部类:简化没有类自身作用的实现类
Comparator<Emp> se=new Comparator<Emp>() { //实现类的类体
@Override
public int compare(Emp o1, Emp o2) {
return Double.compare(o1.getSal(),o2.getSal());
}
};
// lambda表达式:简化匿名内部类对象 要求必须为函数式接口才能简化
// lambda表达式作为实参传递 -> 可以把行为作为参数传递
se=(o1,o2)->o1.getId()- o2.getId();
TreeSet<Emp> ss=new TreeSet<>(se);
TreeSet<Emp> sd=new TreeSet<>(new Sc());
ss.add(new Emp(04,"wang",18000));
ss.add(new Emp(03,"chang",16500));
ss.add(new Emp(02,"zhao",19000));
System.out.println(ss);
}
}
//外部比较器
/*
调用compare方法做两个数据的比较
compare(t1,t2)
返回值:
=0 t1==t2
<0 t1<t2
>0 t1>t2
*/
class Sc implements Comparator<Emp>{
@Override
public int compare(Emp o1, Emp o2) {
return Double.compare(o1.getSal(),o2.getSal());
}
}
package Tuesday;
public class Emp {
private int id;
private String name;
private double sal;
public Emp() {
}
public Emp(int id, String name, double sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
", sal=" + sal +
'}';
}
}
11.14 HashSet
HashSet:
- **底层结构:**哈希表(数组+链表+红黑树)
- **特点:**查询,增删效率高 ,去重,无序
底层是由HashMap维护的
- 遍历:
- foreach
- iterator迭代器
- **新增方法 :**无
- 注意:
- 此类允许null元素
- 此实现不同步
练习:定义HashSet存储javabean类型得到数据,实现去重,测试使用
去重 :数据的类型要求重写hashCode与equals方法
package Tuesday;
import java.util.HashSet;
public class HashSet1 {
public static void main(String[] args) {
HashSet<Test2> sc=new HashSet<>();
sc.add(new Test2("wangchao",22,"男"));
sc.add(new Test2("changkun",29,"男"));
sc.add(new Test2("zhaoshixiang",24,"男"));
sc.add(new Test2("wangchao",22,"男"));
System.out.println(sc);
}
}
package Tuesday;
import java.util.Comparator;
import java.util.Objects;
public class Test2 {
private String name;
private int age;
private String gender;
public Test2() {
}
public Test2(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Test2 test2 = (Test2) o;
return age == test2.age && Objects.equals(name, test2.name) && Objects.equals(gender, test2.gender);
}
@Override
public int hashCode() {
return Objects.hash(name, age, gender);
}
@Override
public String toString() {
return "Test2{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
11.15 Map
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l7dHWyHE-1647963230298)(D:\Notes\笔记.assets\QQ截图20220322153153.png)]
**Map :**无序的,去重的 【键值对数据的集合】
键值对->映射关系
价值对:K-V
K键 :无序的,去重的|唯一的 —> Set
V值 :无序的,可重复 —> Collection
- 注意:
K-V 可以为任意引用数据类型
- 特点:
- 一个key只能对应一个Value
- key相同value覆盖
遍历方式:
1.values 获取所有键值对的值
Collection values() 返回此映射中包含的值的Collection视图
2.keySet 获取所有键值对的key,根据key获取value
Set keySet() 返回此映射中包含的键的Set视图
3.entrySet 获取所有的键值对,每一个键值对都是一个Entry类型 —> 表示一个键值对
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图。
package Tuesday;
import java.util.*;
public class Map1 {
public static void main(String[] args) {
Map<Integer,String> sc=new HashMap<>();
sc.put(1,"浩克");
sc.put(2,"钢铁侠");
sc.put(3,"美国队长");
sc.put(4,"黑寡妇");
sc.put(5,"蜘蛛侠");
System.out.println(sc.get(4));
System.out.println(sc.containsKey(9));
System.out.println(sc.containsValue("蜘蛛侠"));
System.out.println(sc.remove(2));
System.out.println(sc.replace(1, "浩克", "钢铁侠"));
System.out.println(sc.size());
System.out.println("==================");
System.out.println(sc);
Map<Integer,String> ss=Map.of(12,"惊奇队长",23,"灭霸");
System.out.println(ss);
System.out.println("=========值===========");
Collection<String> sf=sc.values();
for (String se:sf){
System.out.println(se);
}
System.out.println("=======键=======");
Set<Integer> sx=sc.keySet();
Iterator<Integer> sz=sx.iterator();
while(sz.hasNext()){
Integer key=sz.next();
System.out.println(key+"--->"+sc.get(key));
}
System.out.println("===========entrySet=============");
Set<Map.Entry<Integer,String>> dui=sc.entrySet();
for (Map.Entry<Integer,String> sv:dui){
System.out.println(sv.getKey()+"--->"+sv.getValue());
}
}
}
11.16 TreeMap
TreeMap :
- **底层:**红黑树
存储键值对类型的数据,自动升序排序,去重的
- 去重,排序:
根据键值对的key实现,与value本身无关
-
注意:
-
TreeSet底层是由TreeMap
-
此实现不同步
-
**测试:**使用TreeMap存储键值对数据,key要求为javabean类型教师数据,value存储教授学科,测试存储练
习是否可以根据key实现去重,测试是否为升序排序,要求根据教师编号做升序排序
去重|排序:根据key的类型的比较规则,key的数据类型实现内部比较器,传递外部比较规则
package Tuesday;
import java.util.Comparator;
import java.util.TreeMap;
public class TreeMap1 {
public static void main(String[] args) {
// 匿名内部类
Comparator<Teacher1> sf=new Comparator<Teacher1>() {
@Override
public int compare(Teacher1 o1, Teacher1 o2) {
return o1.getNum()-o2.getNum();
}
};
// Lambad
sf=(o1,o2)->o1.getNum()-o2.getNum();
TreeMap<Teacher1,String> sc=new TreeMap<>(sf );
sc.put(new Teacher1(1,"zhang",23),"语文");
sc.put(new Teacher1(2,"wang",44),"历史");
sc.put(new Teacher1(3,"chang",26),"英语");
System.out.println(sc);
}
}
class Yest implements Comparator<Teacher1> {
@Override
public int compare(Teacher1 o1, Teacher1 o2) {
return o1.getNum()-o2.getNum();
}
}
package Tuesday;
public class Teacher1 implements Comparable<Teacher1> {
private int num;
private String name;
private int age;
public Teacher1() {
}
public Teacher1(int num, String name, int age) {
this.num = num;
this.name = name;
this.age = age;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher1{" +
"num=" + num +
", name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Teacher1 o) {
return this.num-o.num;
}
}
11.17 HashMap
HashMap :
基于哈希表的Map接口的实现。 此实现提供了所有可选的映射操作,并允许null值和null键。
HashSet 底层是由HashMap
-
**底层结构:**哈希表(数组+链表+红黑树)
-
哈希表:
-
**数组 :**节点数组Node[ ] --> 要求数组的长度为2的整数次幂
-
**Node :**int hash,Object key,Object value,Node next
每个索引位置存储的为一个单向链表的首节点(尾插法)
当链表的长度>8,数组的长度>64,会把链表优化成为红黑树
当链表的长度>8,但是数组的长度不大于64,这时候会实现扩容(数组的扩容)
-
**初始容量:**哈希表中的数组默认的初始长度 16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
数组的容量最大容量 : static final int MAXIMUM_CAPACITY = 1 << 30;
-
**加载因子:**0.75 一般不建议改变
- 默认加载因子 : static final float DEFAULT_LOAD_FACTOR = 0.75f ;
-
**扩容阀值 threshold:**扩容的临界值 数据的个数size>数组的长度*加载因子 就会扩容
-
**扩容机制:**原容量的2倍 int newCap = oldCap << 1
-
**新增功能:**无
-
HashMap的哈希表存储数据的过程:
1.根据key计算哈希值
通过key的hashCode方法的返回值进一步进行hash算法的运算,得到的整数
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
2.调用putVal方法实现添加数据(hash,key,value)
- 判断是否是第一次调用put方法做添加 if ((tab = table) == null || (n = tab.length) == 0)
如果是第一次添加,直接调用resize()实现扩容
-
计算位桶的索引 int index = (n - 1) & hash
-
判断哈希表结构的数组table[index]是否存在数据
① 如果不存在数据,证明没有头节点,创建新节点,放入当前数组的对应索引位置作为头节点
table[index] = new Node<>(hash, key, value, next);
② size数据的个数+1,判断是否>扩容的阀值,如果大于需要调用resize方法进行扩容,如果不大于,不需要扩容直接返回null
if (++size > threshold) resize();
return null;
③ 如果存在数据,作为链表的头结点,遍历这个链表,拿到每一个节点的key与hash值判断是否与要添加的key
和hash相同,如果相同,value覆盖
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
value覆盖之后,返回被覆盖的value
V oldValue = e.value;
e.value = value;
return oldValue;
去重 : 根据key做去重,要求key的数据类型重写hashCode与equals方法
11.19 HashMap与Hashtable
Hashtable 与 HashMap之间的区别:
**共同点 :**都是Map接口的实现类,底层结构都是哈希表
异同点 :
1.继承体系不同
2.线程是否安全不同
HashMap 线程不安全|不同步
Hashtable 线程安全的|同步的
3.扩容机制不同
HashMap扩容机制 :每次扩容原容量的2倍
int newCap = oldCap << 1
Hashtable扩容机制 :原容量的2倍+1
int newCapacity = (oldCapacity << 1) + 1;
4.键值对数据null值的要求不同
HashMap 可以存储null值的key与value
Hashtable key与value都不为null
5.计算hash值与位桶索引index的算法不同
HashMap :
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
int index = (n - 1) & hash
Hashtable :
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
如何处理HashMap线程不安全问题:
1.使用Hashtable
2.使用Collections工具类中static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持
的同步(线程安全)映射
3.juc高级并发编程包 ConcurrentHashMap<K,V> —> 线程安全的哈希表
11.20 Collections工具类
Collections :
操作集合的工具类
静态工厂
void sort(List)
//对List容器内的元素排序,排序的规则是按照升序进行排序
void shuffle(List)
//对List容器内的元素进行随机排列
void reverse(List)
//对List容器内的元素进行逆续排列
void fill(List, Object)
//用一个特定的对象重写整个List容器
int binarySearch(List, Object)
//对于顺序的List容器,采用折半查找的方法查找特定对象