双列集合
双列集合 :由2根单列集合组成的集合叫双列集合
双列集合的特点 : 夫妻对集合/键值对集合
1. 长度可变
2. 只能存对象 (基本数据类型使用包装类型进行存储)
3. 左边的一列集合(键集) : Set 集合 / 右边的一列集合(值集) : Collection集合 (大概率是List)
4. 双列集合键集的特点 : 元素唯一,元素无索引,元素存取无序
双列集合值集的特点 : 元素可重复,元素无索引,元素存取无序(夫唱妇随)
//双列集合 : 一妻多父制 奶量--露露 Pone--露露
5. <K,V> : K类型代表的是键集元素的数据类型 V类型代表的是值集元素的数据类型
成对出现的数据 :
账号--密码,姓名--年龄,学生学号--学生对象, 属性名--属性值
双列集合的体系结构图
Map<K,V>接口
Map<K,V>接口 : 双列集合的根节点
创建集合对象
Map<K,V> 集合名 = new 具体实现类对象<>();//HashMap/TreeMap
<K,V> : K类型代表集合键集的元素类型,V类型代表集合值集的元素类型
增删改查四类功能
增 / 改:
V put(K key, V value) : 往集合中添加一对映射关系
添加成功 : 返回 null
添加失败 : 返回 oldValue 键对应的老值 //当添加的键存在于集合中,修改此键对应的值,并且把老值返回
删 :
V remove(Object key) : 根据传入的键,删除集合中的这一对元素,方法的返回值是被删除的键值对中的值
boolean remove(Object key,Object value) : 按照传入的键值对删除集合中的这一对元素,返回删除是否成功
void clear(): 清空集合中所有的元素
查 :
V get(K key) : 根据传入的键找到其对应的值 -> 通过丈夫找媳妇
int size() : 获取双列集合中元素的个数 (有几对元素)
boolean containsKey(Object key) : 查询集合中是否包含传入的键
boolean containsValue(Object value) : 查询集合中是否包含传入的值
boolean isEmpty() : 查询集合是否为空
Set<K> keySet() : 获取双列集合中所有的键集元素并存储到Set集合中 -> 召集所有的丈夫
Collection<V> values() : 获取双列集合中所有的值集元素并存储到Collection集合中 -> 召集所有的媳妇
遍历
方式1 : keySet()方法和get()方法
a. 召集所有的键
b. 遍历键集 Set集合
c. 通过双列集合对象get方法,键找值
方式2 : 利用结婚证对象进行遍历
a. 召集所有的结婚证对象(键值对对象[Entry]) -> Set<Map.Entry<K,V>> entrySet()
b. 遍历键值对对象集合 Set集合
c. 通过每一个键值对对象获取每一个键值对对象内部封装的键和值
Entry接口 : K getKey()/V getValue()
HashMap<K,V>集合
HashMap<K,V>集合同Map<K,V>接口!
LinkedHashMap<K,V>集合
LinkedHashMap<K,V>集合 和 HashMap<K,V>集合 多了一个 Linked 结构 / 是HashMap的子类
LinkedHashMap<K,V>集合 : 存取无序的集合变成存取有序
TreeMap<K,V>集合
TreeMap<K,V>集合 : 底层数据结构是红黑树结构的双列集合
红黑树结构 : 排序 和 去重 --> 对key进行排序和去重
TreeMap<K,V>集合的特殊构造方法:
TreeMap<K,V>(Comparator<K> comparator)
Hashtable<K,V>集合
Hashtable<K,V>集合 : 最早的双列集合
从JDK1.2板块开始并入到集合体系,被HashMap取代;
Hashtable<K,V>集合 : 线程安全的集合(同步的),效率极低
如果不需要线程安全 : 推荐使用 HashMap 集合
如果需要线程安全 : 推荐使用 ConcurrentHashMap 集合 (线程安全的[同步的],效率虽然低但是比Hashtable高)
虽然Hashtable很废, 但是它的儿子 Properties 非常常用!!
双列集合的案例
student.java:
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
案例1:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
集合嵌套的案例 :
学校集合 <班级类型,班级集合> HashMap<String,ArrayList<Student>>
班级集合 <学生对象> ArrayList<Student>
*/
public class Test1 {
public static void main(String[] args) {
//创建班级集合
ArrayList<Student> basic = new ArrayList<>();
basic.add(new Student("张三",18));
basic.add(new Student("李四",17));
basic.add(new Student("王五",22));
ArrayList<Student> job = new ArrayList<>();
job.add(new Student("赵六",18));
job.add(new Student("田七",17));
job.add(new Student("朱八",22));
//创建学校集合
HashMap<String, ArrayList<Student>> school = new HashMap<>();
school.put("大三班",basic);
school.put("大四班",job);
//遍历集合
Set<Map.Entry<String, ArrayList<Student>>> entries = school.entrySet();
for (Map.Entry<String, ArrayList<Student>> entry : entries) {
//通过键值对对象获取键和值
String className = entry.getKey();
ArrayList<Student> clazz = entry.getValue();
//遍历班级集合
for (Student student : clazz) {
//获取学生的属性
String name = student.getName();
int age = student.getAge();
System.out.println("班级名称 : " + className + ", 学生姓名 : " + name + ", 学生年龄 : " + age);
}
}
}
}
案例2:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
学校集合 : <班级类型,班级集合> <String,HashMap<String,Student>>
班级集合 : <学号,学生对象> -> <String,Student>
*/
public class Test2 {
public static void main(String[] args) {
//学校集合
HashMap<String, HashMap<String, Student>> school = new HashMap<>();
//班级集合
HashMap<String, Student> basic = new HashMap<>();
basic.put("basic001",new Student("张三",18));
basic.put("basic002",new Student("李四",19));
basic.put("basic003",new Student("王五",20));
HashMap<String, Student> job = new HashMap<>();
job.put("job001",new Student("赵六",18));
job.put("job002",new Student("田七",19));
job.put("job003",new Student("朱八",20));
//把班级集合添加到学校集合中
school.put("大三班",basic);
school.put("大四班",job);
//遍历外层集合
Set<String> classNames = school.keySet();
for (String className : classNames) {
//键找值
HashMap<String, Student> clazz = school.get(className);
//遍历内层集合
Set<Map.Entry<String, Student>> entries = clazz.entrySet();
for (Map.Entry<String, Student> entry : entries) {
//获取entry对象中封装的学生学号和学生对象
String sid = entry.getKey();
Student student = entry.getValue();
//取出学生对象的信息
String name = student.getName();
int age = student.getAge();
System.out.println("班级类型 : " + className + " , 学生学号 : " + sid + " , 学生姓名 : " + name + " , 学生年龄 : " + age);
}
}
}
}
泛型
泛型 : generic
泛 : 广泛,泛指,泛泛之辈 --> 意:说不清楚
型 : 数据类型
泛型 -> 说不清楚的引用数据类型
使用过的泛型 : <E> , <K,V> ,<T>
泛型的定义格式 : <字母>
注意事项 :
1. 规范是 字母全是大写 -> 不规范 : <a>
2. 规范是 单个大写字母 -> 不规范 : <MVP>
3. 一个尖括号类可以表示多个泛型类型,中间使用 逗号 分隔 --> <K,V>
泛型的注意事项 :
1. 如果类中定义时有泛型,但是使用时忽略泛型,此时的泛型是 Object
2. 泛型只是停留在编译阶段的类型约束 (泛型概念 : jdk5),如果代码到了运行阶段,泛型就消失了
泛型类
泛型类 : 在类的声明上有泛型类型的声明 (ArrayList<E>)
格式 :
public class 类名<泛型>{
//如果一个类声明时定义了泛型类型,那么久代表在此类中有一种 "泛型类型" 供此类使用
//泛型类型在类中是不知道指向一种具体类型 (只知道是一种不明确的引用数据类型)
//只有等到具体使用此类时,再明确泛型的具体类型
}
泛型方法
泛型方法 : 在方法的声明上有泛型类型的声明
(Arrays 工具类中的 : static <T> void sort(T[] a, Comparator<? super T> c))
格式 :
方法的修饰符 <泛型> 返回值类型 方法名(形参列表){
方法体;
//retrun 值;
}
//泛型方法上的泛型一定在形参上有使用的. 它会根据调用方式传入的实参类型而随时改变
泛型接口
泛型接口 : 在接口的声明上有泛型类型的声明 (ArrayList<E>)
格式 :
public interface 接口<泛型>{
//如果一个接口声明时定义了泛型类型,那么久代表在此接口中有一种 "泛型类型" 供此接口使用
//泛型类型在接口中是不知道指向一种具体类型 (只知道是一种不明确的引用数据类型)
//只有等到具体使用此接口时,再明确泛型的具体类型
}
泛型沿用问题 : 如果子类继承父类/实现类实现父接口,子类没有沿用父类泛型类型,那么子类/实现类就不可以再享受泛型福利了 (例如 : Properties)
泛型的通配符和泛型的上限下限问题
Object > Number > Integer
泛型的通配符 : 用在方法的形参上声明的泛型
? : 任意泛型类型都可以
泛型的下限 : ? super Number (此时的泛型是Number类或者Number的父类)
泛型的上限 : ? extends Number (此时的泛型是Number类或者Number的子类)
不管上限下限都是包含本类的!!