Java编程思想——第17章 容器深入研究(一)
这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法。
一、容器分类
先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性。


二、Collection的功能方法
int size();容器大小
boolean isEmpty();容器内没有元素,返回true
boolean contains(Object o);容器内含有此参数,返回true
Iterator<E> iterator(); 返回一个Iterator<E> 用于遍历
Object[] toArray();返回一个包含所有容器中元素的数组
<T> 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 Spliterator<E> spliterator()* 1.8新增 并行遍历迭代器 不影响主线程的遍历器 举例:
    public static void main(String[] args) {
        List<String> list = 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 Stream<E> stream()返回一个顺序流
default 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已包含的方法外还增加了
boolean addAll(int index, Collection<? extends E> c);从索引位置插入参数中元素
default void replaceAll(UnaryOperator<E> operator) *1.8新增 将几何中元素替换成参数中的 举例:
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.replaceAll(a -> a + 1);//将元素更新为+1的元素
default void sort(Comparator<? super E> c) c:自定义排序规则 举例:
List<User> list = new ArrayList();
list.add(u1);
list.add(u2);
list.sort((o1, o2) -> {
Integer age1 = o1.getAge();
Integer age2 = o2.getAge();
return age1.compareTo(age2);
}); //自定义年龄排序
E get(int index); 获取索引位置的元素
E set(int index, E element); 将元素放入索引位置
void add(int index, E element); 在索引位置增加元素
E remove(int index); 移除索引位置的元素
int indexOf(Object o); 返回元素第一次出现时的索引位置
int lastIndexOf(Object o); 返回元素最后一次出现时的索引位置
ListIterator<E> listIterator(); 迭代器
ListIterator<E> listIterator(int index); 从索引位置迭代
List<E> subList(int fromIndex, int toIndex); 按照索引开始结束位置截取
------LinkLIst独有的方法-------
public void addFirst(E e) 在首位增加
public void addLast(E e) 在尾部增加 public E removeFirst(E e) 移除首位
public 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创建自定义元素类型:
class SetType {
    Integer i;
    String str;
    @Override
    public boolean equals(Object o) {
        return o instanceof SetType && (i.equals(((SetType) o).i)) && (str.equals(((SetType) o).str));
    }
}
class HashType extends SetType {
    /**
     * 这里涉及到如何重写hashCode:
     * 1.取一个初始值17
     * 2.对每一个重要字段(equals()方法里面比较的字段)进行一下操作:
     * a.filedHashValue = filed.hashCode();
     * b.result = result*31+filedHashValue;
     */
    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + (i == null ? 0 : i.hashCode());
        result = 31 * result + (str == null ? 0 : str.hashCode());
        return result;
    }
}
class TreeType extends SetType implements Comparable<TreeType> {
    /**
     * compare要指定比较字段
     */
    @Override
    public int compareTo(TreeType arg) {
        return (arg.i < i ? -1 : (arg.i.equals(i) ? 0 : 1));
    }
}
Java编程思想——第17章 容器深入研究(一)的更多相关文章
- Java编程思想——第17章 容器深入研究 读书笔记(三)
		
七.队列 排队,先进先出. 除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: ad ...
 - Java编程思想——第17章 容器深入研究(two)
		
六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add ...
 - Java编程思想——第17章 容器深入研究 读书笔记(二)
		
五.List的功能方法 排除Collection已包含的方法外还增加了 boolean addAll(int index, Collection<? extends E> c);从索引位置 ...
 - Java编程思想——第17章 容器深入研究 读书笔记(一)
		
这一章将学习散列机制是如何工作的,以及在使用散列容器时怎么样编写hashCode()和equals()方法. 一.容器分类 先上两张图 来概况完整的容器分类 再细说都为什么会有那些特性. 二.填充容器 ...
 - Java编程思想——第17章 容器深入研究 读书笔记(四)
		
九.散列与散列码 HashMap使用equals()判断当前的键是否与表中存在的键相同. 正确的equals()方法需满足一下条件: 1)自反性.x.equals(x) 是true; 2)对称性.x. ...
 - Java编程思想(11~17)
		
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...
 - Java编程思想 第21章 并发
		
这是在2013年的笔记整理.现在重新拿出来,放在网上,重新总结下. 两种基本的线程实现方式 以及中断 package thread; /** * * @author zjf * @create_tim ...
 - java编程思想笔记(第一章)
		
Alan Kay 第一个定义了面向对象的语言 1.万物皆对象 2.程序是对象的集合,他们彼此通过发送消息来调用对方. 3.每个对象都拥有由其他对象所构成的存储 4.每个对象都拥有其类型(TYpe) 5 ...
 - Java编程思想——第14章 类型信息(一)
		
运行时类型信息使得你可以在程序运行时发现和使用类型信息.Java是如何让我们在运行时识别对象和类的信息得呢? 主要有两种方式:1.传统RTTI,他假定我们在编译期间已经知道了所有类型:2.反射,它允许 ...
 
随机推荐
- 大型情感剧集Selenium:2_options设置 #华为云·寻找黑马程序员#
			
上集回顾 昨天说简单介绍了什么是selenium,它能干what,和发展史与梗概.当的是python如何通过pip安装selenium,并下载对应浏览器的webdriver. 最后简单通过一个Demo ...
 - luogu P3807 【模板】卢卡斯定理
			
求 C(n,n+m)%p C(m,n)%p=C(m%p,n%p)*C(m/p,n/p) #include<cstdio> #include<cstring> #include& ...
 - 利用Mitmproxy抓包
			
http://mrpeak.cn/blog/mitmproxy/ 和Charles同样强大的免费抓包软件. 它是在终端操作的,界面没有Charles那么可视化.不过也很好用,通过各种快捷键操作,效 ...
 - HDU5470 Typewriter (SAM+单调队列优化DP)
			
Typewriter Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Tota ...
 - 第二节.NET两种交互模式:c/s和b/s
			
1.什么是c/s c指的是client(客户端),s指的是服务器模式,c/s是client/Server的缩写,客户端需要安装专业的客户端软件,如我们用的qq.酷狗音乐等客户端软件 ...
 - springboot中实现kafa指定offset消费
			
kafka消费过程难免会遇到需要重新消费的场景,例如我们消费到kafka数据之后需要进行存库操作,若某一时刻数据库down了,导致kafka消费的数据无法入库,为了弥补数据库down期间的数据损失,有 ...
 - Day 06 流程控制和爬虫基础2
			
目录 if 判断 单分支结构 双分支结构 多分支结构 for循环 for循环的基本用法 for循环嵌套 break continue 爬虫基础2 爬取豆瓣TOP250 爬取豆瓣数据接口(异步数据) 爬 ...
 - java发送邮件基础方法(另附部分主流邮箱服务器地址、端口及设置方法)
			
java发送邮件基础方法,可通过重载简化参数 import java.io.File; import java.io.UnsupportedEncodingException; import java ...
 - Vue AES+MD5加密 后台解密
			
前端VUE vue项目中安装crypto-js npm install crypto-js --save-dev CryptoJS (crypto.js) 为 JavaScript 提供了各种各样的加 ...
 - 进程-(process)、线程-(Thread)
			
进程和线程之间的区别: 内存之间的区别: 进程之间不可以共享内存空间,每个进程都有各自独立的内存空间: 线程之间则是可以共享一个进程里的内存空间: 通信机制方面的区别 默认情况下,进程之间很难互通的, ...