这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法。
一、容器分类
先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性。
二、填充容器(省略):创建Collection和Map的生成器 用于测试,没什么知识点提炼。
三、Collection的功能方法
int size();容器大小
boolean isEmpty();容器内没有元素,返回true
boolean contains(Object o);容器内含有此参数,返回true
Iteratoriterator(); 返回一个Iterator 用于遍历
Object[] toArray();返回一个包含所有容器中元素的数组
T[] toArray(T[] a); 返回一个包含所有容器内元素的数组,但返回类型为T而不简单是Object
boolean add(E e);像容器添加内容添加失败返回false(可选的)
boolean remove(Object o);移除一个元素,成功返回true(可选的)
boolean containsAll(Collection> c);若包含参数中的所有元素,返回true
boolean addAll(Collection extends E> c);添加参数中所有元素,有任意元素添加成功则返回true(可选的)
boolean removeAll(Collection> c);一处参数中所有元素,有任何元素移除则返回true(可选的)
default boolean removeIf(Predicate super E> filter) * 1.8新增 移除满足参数参数条件的元素(可选的)
举例:names.removeIf(a->a.startsWith("徐")); 删除开头为徐的名字 strings.removeIf(a->a.equals("hello")); 删除hello这个元素。
boolean retainAll(Collection> c);只保存参数中元素,如果Collection发生变化返回true(可选的)
void clear();清空集合(可选的)
boolean equals(Object o);于其他集合对比是否相等
int hashCode();返回集合的哈希值:一个用来进行hash操作的整型代号
default Spliteratorspliterator()* 1.8新增 并行遍历迭代器 不影响主线程的遍历器
举例:
public static void main(String[] args) { Listlist = new LinkedList<>(); for (int i = 0; i < 20000; i++) { list.add("" + i); } list.spliterator().forEachRemaining(e -> System.out.println(e)); System.err.println("end"); }
输出结果:
default Streamstream()返回一个顺序流
default StreamparallelStream()返回一个并行流
Java8新增Stream:https://www.cnblogs.com/xcgShare/p/11686008.html
注意:Collection中不包括随机访问所选元素的get()方法,因为Collection包括Set,而Set是自己维护内部顺序的,这使得随机访问没有意义,因此如果想访问Collection中的元素,就必须使用迭代器。
四、可选方法
执行各种添加和移除操作在Collection中都是可选操作。这意味着实现类并不需要为这些方法提供功能定义。
如果一个操作时可选的,编译器仍旧会严格要求你只能调用该接口中的方法,并且将Collection当作参数接受的大部分方法只会从该Collection中读取,而Collection的读取方法都是不可选的。
为什么要将方法定义为可选呢?
原因很简单 就是防止在设计中出现接口爆炸的情况。
未获支持的操作
最常见的未获支持操作,都是源于背后有固定尺寸的数据结构支持的容器。比如:Arrays.asList()会生成一个List,它是基于固定大小的数组,仅支持那些不会改变数组大小的操作。
任何会引起对底层数据结构的尺寸进行修改的方法 都会产生一个UnsupportedOperationException异常,以表示对未获支持操作的调用。
应该把Arrays.asList()的结果作为构造器的参数传递给任何Collection(或者使用addAll())来生成可以使用所有方法的普通容器。