0%

Java 通用容器类和总结(二):Collections

1. 类 Collections 以静态方法的方式提供了很多通用算法和功能,这些功能大概的分类

  • 对容器接口对象进行操作

    • 查找和替换
    • 排序和调整顺序
    • 添加和修改
  • 返回一个容器接口对象

    • 适配器:将其他类型的数据转换为容器接口对象
    • 装饰器:修饰一个给定容器接口对象,增加某种性质

2. 上述分类功能的好处是

  • 第一类:是针对容器接口的通用操作,是面向接口编程的一种体现,是接口的典型用法
  • 第二类:是为了使更多类型的数据更为方便和安全地参与到容器类协作体系中

3. 类 Collections 包含哪些查找和替换方法

  • 二分查找
  • 查找最大值/最小值
  • 查找元素出现次数
  • 查找List
  • 查看两个集合是否有交集

4. 针对 List 接口对象,Collections 除了提供基础的排序,还提供了哪些调整顺序的方法

  • 交换元素位置翻转列表顺序随机化重排循环移位
  • 其中,循环移位的内部实现比较巧妙,根据列表大小和是否实现了 RandomAccess 接口,有两个算法,都比较巧妙,两个算法在《编程珠玑》的 2.3 节有描述

5. 适配器的概念是

  • 就是将一种类型的接口转换成另外一种接口

6. Collections 提供的类似于适配器的方法有

  • 空容器方法:类似于将 null 或 ‘空’ 转换为一个标准的容器接口对象
  • 单一对象方法:将一个单独的对象转换为一个标准的容器接口对象
  • 其他适配器方法:将 Map 转换为 Set

7. 一个空容器接口对象有什么作用呢,和新建一个对象的区别是什么,空容器对象有什么限制吗

  • 作用:空容器接口对象经常用作方法返回值,避免返回 null 导致的代码检查繁琐和调用者忘记检查继而抛出的空指针异常,即:方便调用者安全地进行统一处理
  • 区别Collections 的静态的空容器对象方法返回的是一个静态不可变对象,可以节省创建新对象的内存和时间开销。
  • 限制空容器接口对象不能用于写入,分析源码可知是因为它的内部实现是一个私有静态内部类,不支持修改操作,否则会抛出 UnsupportedOperationException 异常
  • 说明:在 Java 9 中,可以使用 ListMapSet 不带参数的 of() 方法返回一个空的只读容器对象。即:List list = Collections.emptyList()List list = List.of() 效果是相同的

8. 单一对象方法的作用是什么,相比新建容器对象并添加元素有什么好处,有什么限制

  • 作用:可以将一个单独的对象转换为一个标准的容器接口对象,经常用于构建方法返回值构建方法参数
  • 好处:相比新建容器对象并添加元素,单一对象方法更为简洁方便实现更为高效,它们的实现类都针对单一对象进行了优化
  • 限制单一对象方法返回的也是不可变对象,只能用于读取,写入会抛出 UnsupportedOperation 异常
  • 说明:在 Java 9 中,可以使用 ListMapSetof() 方法达到和 Collections 的单一对象方法同样的功能。即:Set<String> b = Collections.singleton("b");Set<String> b = Set.of("b"); 效果是相同的

9. 装饰器的概念是

  • 装饰器接受一个接口对象,并返回一个同样接口的对象
  • 新对象可能会扩展一些新的方法或属性,扩展的方法或属性就是所谓的“装饰”
  • 也可能会对原有的接口方法做一些修改,达到一定的“装饰”目的

10. Collections 提供的装饰器方法是怎样的

  • Collections 有三组装饰器方法,它们的返回对象都没有新的的方法或属性,但改变了原有的接口方法的性质
  • 经过“装饰”后,它们更为安全了,具体分别是写安全类型安全线程安全

11. Collections 的装饰器方法是怎样支持写安全的

  • Collections 提供了一组 unmodifiableXXX() 方法,这些方法就是使容器对象变为只读的,写入会抛出 UnsupportedOperationException 异常
  • 之所以要变为只读,原因是有典型的场景:需要传递一个容器对象给一个方法,这个方法可能是第三方提供的,为避免第三方误写,所以在传递前变为只读的

12. Collections 的装饰器方法是怎样支持类型安全的

  • 类型安全:指确保容器中不会保存错误类型的对象
  • 之所以容器有时会允许保存错误类型对象,是因为 Java 是通过类型擦除来实现泛型的,而且类型参数是可选的。正常情况下,我们会加上类型参数,让泛型机制来保证类型的正确性。但是,由于泛型是 Java 5 以后才加入的,之前的代码可能没有类型参数,而新的代码可能需要与老的代码互动
  • 此时,为了避免老的代码用错类型,确保在泛型机制失灵的情况下类型的正确性,可以在传递容器对象给老代码之前,使用 Collections 提供的静态装饰方法 chedkedXXX(),这些方法都需要传递类型对象,使容器对象的方法在运行时检查类型的正确性,如果不匹配,会抛出 ClassCastException 异常,从而避免错误类型的数据插入

13. Collections 的装饰器方法是怎样支持线程安全的

  • 之前的各种容器类基本都是线程不安全的。即,如果多个线程同时读写同一个容器对象,是不安全的
  • Collections 提供了一组 synchronizedXXX() 方法,可以将一个容器对象变为线程安全的。这些方法都是通过给所有容器方法加锁来实现的
  • 加锁这种实现并不是最优的,Java 提供了很多专门针对并发访问的容器类
-------------------- 本文结束感谢您的阅读 --------------------