Map & 泛型(双列)

1. 什么是 Map

  1. API文档描述:将键映射到值的对象(key-value)。一个映射(一个Map对象)不能包含重复的键;效率高
  • 键(可以) : 本质也是一个数据(不可以重复)。key 通过 hashcode、equals 判断是否重复。
  • 值(value) : 本质也是一个数据(可重复)

  • 键值对: 就是一对(和两个是有区别的),一对一般是有某种关系
  • 映射 : 上面说的一个映射就看成是一个Map对象 key对应value是一种映射关系
  1. Object put(Object key,Object value): 如果当前添加的这个key已经存在了,会覆盖这个键之前的值,返回的是之前的value值。
  2. boolean containsKey(Object key):判断Map集合中是否包含当前的传入的key。
  3. boolean containsValue(Object value) : 判断Map集合中是否包含当前的传入的value。
  4. Object get(Object key) : 根据指定的键key找到对应的值,如果没有找到返回 null。
  5. remove(Object key) : 删除指定key对应的那一对。

重要方法列表:

  1. Collection values() : 返回一个Map中的所有的value值 Collection集合。
  2. Set keySet() :返回所有的key值的集合(key是唯一的,所以返回的是Set集合)。
  3. Set entrySet(): 返回所有的entry对象(key是唯一的,所以返回的是Set集合)。(底层将 key、vaule 封装为Entry 对象。)

问题:为什么 values() 方法返回的是 Collection,而keySe() 、entrySet() 返回的是Set?

Key entry 都不能重复的-Set

2. HashMap (无序)

  1. 允许 key 、value 值为null,但只允许 一个null 值的键
  2. hashMap 是线程不安全的。
  3. 默认容量 为 16。
  4. hashMap 是如何扩容的?当实际值 等于 容量的 百分之75 扩容。
  5. HashMap 是无序的:放进去的数据和取出来的数据不一样。
  6. 超高的访问速度。

2.1. HashMap 原理(面试题)

1. HashMap 是键值对的,它怎么存数据的?

        将 key 和 value 封装成对象 Entry

2. 每一次存进去的值放在数组的那个位置?

        先计算 key 的Hash值 ②Hash % 数组.length

3. 如果key 计算出来的 Hash 最后 % 的位置一致怎么办?

        Hash冲突

        链表(拉链法),解决hash冲突。

  •  当 链表的结构 > 8 时,链表结构 变为 红黑树。
  •   如果数节点 < 6 又从数结构转为链表

 4. HashMap 底层是什么? 

        数组+ 链表 +红黑树

3. LinkedHashMap(有序)

  1. 有序的,线程不安全的
  2. LinkedHashMap 通过维护一个额外的双向链表保证了迭代顺序。(LinkedHashMap = HashMap + 双向链表)

4. HashTable(无序)

  1. key 不允许为null,value 不允许 为null
  2. HashTable 的 线程安全的,但是效率低。

4.1. Properties(重点)(线程安全)

Properties 类是 Java 中用于处理配置文件的工具类,它继承自 Hashtable 类,实现了 Map 接口。

  1. Properties 类表示了一个持久的属性集 。
  2. properties 可以保存到流中 或 从流中加载。
  3. key、values 存储的类型--String (属性列表中的每个键及其对应的值都是一个字符串)。

4.1.1. Properties 作用

使用该类可以更好的处理文件:

  • 配置文件管理: 主要用于读取和保存应用程序的配置信息,例如数据库连接信息、用户设置等。
  • 国际化: 用于加载不同语言的资源文件,方便国际化应用程序。
  • 持久化: 可以将配置信息持久化到文件,以便下次程序启动时重新加载

4.1.2. Properties 重要方法

1. String getProperty(String key) :使用此属性列表中指定的键搜索属性。

2. String getProperty(String key, String defaultValue) :使用此属性列表中指定的键搜索属性。

3. void list(PrintStream out) : 将此属性列表打印到指定的输出流。

        void list(PrintWriter out) :将此属性列表打印到指定的输出流。 

4. void load(Reader reader) :以简单的线性格式从输入字符流读取属性列表(关键字和元素对)。

        void load(InputStream inStream) :从输入字节流读取属性列表(键和元素对)。

5. Object setProperty(String key, String value) : 设置 键值对。

4.1.3. Properties 的应用场景(读写资源文件)

1. Properties 中 通过 list 方法将值 持久化到文件中

Properties pp = new Properties();
pp.setProperty("XXXX", "OOOO");
pp.setProperty("YYYY", "JJJJ");
PrintStream ps = new PrintStream("F:/qq.txt");
pp.list(ps);

    2. Properties 中 通过 load 将文件中的 值(String类型键值对)加载到 Properties 对象

    Properties p1 = new Properties();
    FileInputStream fis = new FileInputStream("D:/qq1.txt");
    p1.load(fis);

    5. TreedMap(排序)

    根据key排序。

    5.1. 自然排序

    类实现 comparable 接口重写 compareTo 方法

    5.2. 定制排序

    自定义一个类实现Comparator接口,重写 compare() 方法。

    5.3. ConcurrentHashMap

    现在安全的Map 的用 ConcurrentHashMap

    考虑线程安全或者写入速度的话,可以使用 HashTable,JDK8后建议使用 ConcurrentHashMap替代HashTable,既能获取超高的访问速度,又能保证线程安全

    6. Collections

    7. 泛型

    7.1. 泛型的认识

    • 泛型的 本质是 参数化类型,也就是说所操作的 数据类型被指定为一个参数。
    • 这种参数类型可以用在 类、接口 和 方法的创建中;分别被称为 泛型类、泛型接口、泛型方法。

    简单的理解:就是在设计的类、接口 等 的时候,没有规定具体是什么类型的参数,在实例化 或调用的时候再 传入具体的类型,告诉编译期这是 什么类型。

    注意:

    1. 泛型 不会影响 程序的运行的速度,因为在编译期就会直接编译成具体的类型。
    2. 使用泛型的方法或实例化泛型的类,只能传入引用数据类型,不能传入基本数据类型。

    7.2. 规则限制

    1. 泛型的类型参数 只能是 引用数据类型,不能是基本数据类型。
    2. 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
    3. 泛型的类型参数可以有多个。

    规范的写法应该是使用一些字母(常见的字母):

    E Element 元素

    T Type 类型

    K Key 键

    V Value 值

    7.3. 泛型的作用

    在编译的时候 检查 类型安全,并且所有的 强制转换都是自动和隐式的,以提高代码的重用率

    7.4. 范式类

    格式

    修饰符 class 类名<类型>{ }

    
    /**
     * 设计一个类 表示 飞机大战的地图
     */
    public class MapPoint {
        int x;
        int y;
    }
    
    /**
     * 设计一个类 表示 世界地图
     */
    class MapPoint1 {
        BigDecimal x;
        BigDecimal y;
    }
    
    /**
     * 设计一个类 表示 平面坐标
     */
    class MapPoint2 {
        double x;
        double y;
    }
    class Point<T1,T2> {
        T1 x;
        T2 y;
    }
    class Test{
        public static void main(String[] args) {
            Point<Integer,Character> point1 = new Point<Integer,Character>();
            Point<User,Dog> point2 = new Point<User,Dog>();
        }
    }
    

    7.5. 泛型方法

    格式:

    格式:修饰符<类型> 返回值类型 方法名(类型 变量名){ };

    例:设计一个方法 将2个数组 合并 并排序

    public class GenericMethod {
        public static void main(String[] args) {
    
            Integer[] a1 = {3,1,2,5,8,4};
            Integer[] a2 = {9,2,6};
            merge(a1,a2);
        }
        // 设计一个方法  将2个数组 合并 并排序
        // 泛型是在什么时候被确定的?  创建对象 和 调用的时候才能被 确定
        // 告诉编译器 这是一个 泛型方法  在返回值前 写上 <T> 表示这个是一个 泛型方法
        public static <T> void merge(T[] arr1,T[] arr2){
            // 泛型不能实例化 泛型是不能new 对象的
            //        T[] newArr = new T[arr1.length + arr2.length];
            // 创建新数组 并 将arr1的元素 塞进去
            T[] ts = Arrays.copyOf(arr1, arr1.length + arr2.length);
            // 将arr2的数据塞进去
            // 源 源位置  目标 目标位置  长度
            System.arraycopy(arr2,0,ts,arr1.length,arr2.length);
            Arrays.sort(ts);
            System.out.println(Arrays.toString(ts));
        }
    }

    7.6. 泛型的上下限

    7.6.1. 设置泛型的上限

    <? extends 类型>

    :List <? extends Number>: 它表示List集合中 元素的类型是 Number或者 其子类型

    7.6.2. 设置泛型的下限

    <? super 类型>

    例:List<? super Number> :它表示List集合中 元素的类型是 Number 或者 其父类型

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值