15.双列集合和泛型

本文详细介绍了Java中的双列集合Map,包括HashMap、TreeMap和LinkedHashMap等实现类。Map接口是双列集合的根节点,支持键值对存储,键具有唯一性。HashMap提供快速存取,TreeMap则基于红黑树实现排序,LinkedHashMap保持插入顺序。文章还涉及泛型的概念和使用,并通过实例展示了如何在实际编程中操作Map集合。
摘要由CSDN通过智能技术生成

双列集合

双列集合 :由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的子类)

    不管上限下限都是包含本类的!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值