Java编程思想——第17章 容器深入研究(一)

  这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法。

一、容器分类

  先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性。

 

 

二、Collection的功能方法

1int size();容器大小  2 3boolean isEmpty();容器内没有元素,返回true 4 5boolean contains(Object o);容器内含有此参数,返回true 6 7Iterator<E> iterator(); 返回一个Iterator<E> 用于遍历 8 9Object[] toArray();返回一个包含所有容器中元素的数组 10 11<T> T[] toArray(T[] a); 返回一个包含所有容器内元素的数组,但返回类型为T而不简单是Object 12 13boolean add(E e);像容器添加内容添加失败返回false(可选的) 14 15boolean remove(Object o);移除一个元素,成功返回true(可选的) 16 17boolean containsAll(Collection<?> c);若包含参数中的所有元素,返回true 18 19boolean addAll(Collection<? extends E> c);添加参数中所有元素,有任意元素添加成功则返回true(可选的) 20 21boolean removeAll(Collection<?> c);一处参数中所有元素,有任何元素移除则返回true(可选的) 22 23default boolean removeIf(Predicate<? super E> filter) * 1.8新增 移除满足参数参数条件的元素(可选的)举例:names.removeIf(a->a.startsWith("徐")); 删除开头为徐的名字 strings.removeIf(a->a.equals("hello")); 删除hello这个元素。 24 25boolean retainAll(Collection<?> c);只保存参数中元素,如果Collection发生变化返回true(可选的) 26 27void clear();清空集合(可选的) 28 29boolean equals(Object o);于其他集合对比是否相等 30 31int hashCode();返回集合的哈希值:一个用来进行hash操作的整型代号 32 33default Spliterator<E> spliterator()* 1.8新增 并行遍历迭代器 不影响主线程的遍历器 举例: 34 35public static void main(String[] args) { 36 List<String> list = new LinkedList<>(); 37 for (int i = 0; i < 20000; i++) { 38 list.add("" + i); 39 } 40 list.spliterator().forEachRemaining(e -> System.out.println(e)); System.err.println("end"); }

输出结果:

1default Stream<E> stream()返回一个顺序流 2 3default Stream<E> parallelStream()返回一个并行流 Java8新增Stream:Java8两大特性(一)——Stream注意:Collection中不包括随机访问所选元素的get()方法,因为Collection包括Set,Set是自己维护内部顺序的,这使得随机访问没有意义,因此如果想访问Collection中的元素,就必须使用迭代器。

三、可选方法 

  执行各种添加和移除操作在Collection中都是可选操作。这意味着实现类并不需要为这些方法提供功能定义。如果一个操作时可选的,编译器仍旧会严格要求你只能调用该接口中的方法,并且将Collection当作参数接受的大部分方法只会从该Collection中读取,而Collection的读取方法都是不可的。

  为什么要将方法定义为可选呢?原因很简单 就是防止在设计中出现接口爆炸的情况。

未获支持的操作:

  最常见的未获支持操作,都是源于背后有固定尺寸的数据结构支持的容器。比如:Arrays.asList()会生成一个List,它是基于固定大小的数组,仅支持那些不会改变数组大小的操作。任何会引起对底层数据结构的尺寸进行修改的方法 都会产生一个UnsupportedOperationException异常,以表示对未获支持操作的调用。应该把Arrays.asList()的结果作为构造器的参数传递给任何Collection(或者使用addAll())来生成可以使用所有方法的普通容器。

四、List的功能方法

 排除Collection已包含的方法外还增加了

1boolean addAll(int index, Collection<? extends E> c);从索引位置插入参数中元素 2 3default void replaceAll(UnaryOperator<E> operator) *1.8新增 将几何中元素替换成参数中的 举例: 4 5List<Integer> list = new ArrayList(); 6 list.add(1); 7 list.add(2); 8 list.replaceAll(a -> a + 1);//将元素更新为+1的元素 9 10default void sort(Comparator<? super E> c) c:自定义排序规则 举例: 11 12List<User> list = new ArrayList(); 13 list.add(u1); 14 list.add(u2); 15 list.sort((o1, o2) -> { 16 Integer age1 = o1.getAge(); 17 Integer age2 = o2.getAge(); 18 return age1.compareTo(age2); }); //自定义年龄排序 19 20E get(int index); 获取索引位置的元素 21 22E set(int index, E element); 将元素放入索引位置 23 24void add(int index, E element); 在索引位置增加元素 25 26E remove(int index); 移除索引位置的元素 27 28int indexOf(Object o); 返回元素第一次出现时的索引位置 29 30int lastIndexOf(Object o); 返回元素最后一次出现时的索引位置 31 32ListIterator<E> listIterator(); 迭代器 33 34ListIterator<E> listIterator(int index); 从索引位置迭代 35 36List<E> subList(int fromIndex, int toIndex); 按照索引开始结束位置截取------LinkLIst独有的方法------- 37 38public void addFirst(E e) 在首位增加 39 40public void addLast(E e) 在尾部增加public E removeFirst(E e) 移除首位 41 42public E removeLast(E e) 移除尾部这四个方法的合理利用可以利用LinkList实现栈(先进后出)和队列(先进先出)

五、Set和存储顺序

  不同的Set实现具不同的行为,并且对于在特定的Set中放置的元素类型也有不同的要求。

  Set(interface): 存入Set的每个元素都必须是唯一的,因为set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set和Collection有完全一样的接口。Set接口不保证维护元素的次序。

  HashSet *:为快速查找而设计的Set。存入HashSet的元素必须定义hashCode()。因为速度所以首选,神秘的排序。

  TreeSet:保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。元素必须实现Comparable接口。

  LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素顺序(插入顺序)。于是在使用迭代器遍历Set时,结果会按元素插入顺序显示,元素也必须实现hashCode()方法。

  必须为Set创建equals()方法,只有HashSet和LinkHashSet需要hashCode()方法。但是良好的编程风格应该是重写equals()时跟着重写hashCode()。

如何为Set创建自定义元素类型:

1class SetType { 2 Integer i; 3 4 String str; 5 6 @Override 7 public boolean equals(Object o) { 8 return o instanceof SetType && (i.equals(((SetType) o).i)) && (str.equals(((SetType) o).str)); 9 } 10} 11 12class HashType extends SetType { 13 /** 14 * 这里涉及到如何重写hashCode: 15 * 1.取一个初始值17 16 * 2.对每一个重要字段(equals()方法里面比较的字段)进行一下操作: 17 * a.filedHashValue = filed.hashCode(); 18 * b.result = result*31+filedHashValue; 19 */ 20 @Override 21 public int hashCode() { 22 int result = 17; 23 result = 31 * result + (i == null ? 0 : i.hashCode()); 24 result = 31 * result + (str == null ? 0 : str.hashCode()); 25 return result; 26 } 27} 28 29class TreeType extends SetType implements Comparable<TreeType> { 30 31 /** 32 * compare要指定比较字段 33 */ 34 @Override 35 public int compareTo(TreeType arg) { 36 return (arg.i < i ? -1 : (arg.i.equals(i) ? 0 : 1)); 37 } 38}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Java编程思想——第17章 容器深入研究(一) - HelloWorld