[Think In Java]基础拾遗3 - 容器、I/O、NIO、序列化
目录
第十一章 持有对象
第十七章 容器深入研究
第十八章 Java I/O系统
第十一章 持有对象
1. java容器概览
java容器的两种主要类型(它们之间的主要区别在于容器中每个“槽”保存的元素个数):Collection和Map。
(1)Collection是一个独立元素的序列,这些元素都服从一条或者多条规则。Collection概括了序列的概念——一种存放一组对象的方式。
- List:按照插入的顺序保存元素(ArrayList,LinkedList)
- Set:不能有重复元素(HashSet,TreeSet,LinkedHasSet)
- Queue:按照排队规则来确定对象产生的顺序(按排队时间长短即FIFO、按优先级高低)
(2)Map是一组成对的“键值对”对象,允许使用键来查找值。
- HashMap:无序
- TreeMap:按照比较结果的升序保存键
- LinkedHashMap:按照插入顺序保存键
2. 相关工具类java.util.Arrays类和java.util.Collections类。
(1)添加一组元素
Arrays.asList();
Collections.asList();
(2)容器的打印
Arrays.toString();
3. 迭代器
遍历容器而不关心容器的具体类型。迭代器也是一种设计模式。(和C++中的迭代器类似)
Collection接口有一个iterator()方法返回一个Iterator对象,也就是说每个继承自Collection的容器都可以迭代(Collection接口继承自Iterable接口)。Iterator有如下方法:
boolean hasNext() :如果仍有元素可以迭代,则返回 true。
E next() :返回迭代的下一个元素。
void remove() :从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作,不是所有的容器都实现了该方法)。
4. ListIterator
ListIterator继承自Iterator。Iterator只能向前移动,但是ListIterator可以双向移动,ListIterator只能用于各种List。
5. Set
将两个相同的对象放入Set中是不行的。Set是基于对象的值来确定归属性的。
HashSet:基于hash函数;TreeSet:基于红黑树;LinkedHashSet:hash函数+链表。
TreeSet 使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。
String类有一个比较器String.CASE_INSENSITIVE_ORDER;
6. PriorityQueue
一个基于优先级堆的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。
7. 简单的容器分类
第十七章 容器深入研究
1. 完整的容器分类法
下图展示了Java容器类库的完备图,包括抽象类和遗留构件(不包括Queue的实现)。
常用的容器用黑色粗线框表示,点线框表示接口,虚线框表示抽象类,实线框表示类,空心箭头表示实现关系。Produce表示任意的Map对象可以生成Collection对象,任意的Collection对象可以生成Iterator对象。
2. 容器总结
下面以表格的形式总结List、Set、Map接口及各实现类的特性:
特性 |
实现类 |
实现类特性 |
对放置的元素的要求 |
|
List |
线性、有序的存储容器,可通过索引访问元素get(n) |
ArrayList |
数组实现。非同步。 |
|
Vector |
类似ArrayList,同步。 |
|||
LinkedList |
双向链表。非同步。 |
|||
Set |
元素不能重复,元素必须定义equals()方法 |
HashSet |
为快速查找设计的Set |
元素必须定义hashCode() |
TreeSet |
保持次序的Set,底层为树结构 |
元素必须实现Comparable接口 |
||
LinkedHashSet |
内部使用链表维护元素的顺序(插入的次序) |
元素必须定义hashCode() |
||
Map |
保存键值对成员,Map中的所有键必须定义equals()方法 |
HashMap |
基于哈希表的 Map 接口的实现,满足通用需求 |
键必须有恰当的hashCode(),如果修改了equals方法,需同时修改hashCode方法 |
TreeMap |
默认根据自然顺序进行排序,或者根据创建映射时提供的 Comparator进行排序 |
键成员要求实现caparable接口,或者使用Comparator构造TreeMap。键成员一般为同一类型。 |
||
LinkedHashMap |
类似于HashMap,但迭代遍历时取得“键值对”的顺序是其插入顺序或者最近最少使用的次序 |
与HashMap相同 |
||
IdentityHashMap |
使用==取代equals()对“键值”进行比较的散列映射 |
成员通过==判断是否相等 |
||
WeakHashMap |
弱键映射,允许释放映射所指向的对象 |
|||
ConcurrentHashMap |
线程安全的Map |
说明:
(1)各种Queue和Stack的行为,完全可以LinkedList提供支持,上述表格不包含Queue。
(2)但凡是和hash相关的,必然会设计到hashCode方法,因为要根据返回的哈希码去计算该对象在哈希表中的位置;但凡是和Tree相关的,必然会设计到Comparable接口,因为要涉及到排序。
(3)如果要进行大量的随机访问,就是用ArrayList;如果要经常从表中间插入或删除元素,则应该用LinkedList。遍历的时候,对于ArrayList优先选择get方式,LinkedList优先选择iterator方式。
(4)Collection继承了Iterable接口,故所有的Collection对象都可以使用foreach方式,对元素进行遍历。所有的Collection对象都hiuforeach循环可以与任何实现了Iterable接口的对象一起工作。
(5)自定义类作为HashMap/HashSet/LinkedHashMap/LinkedHashSet的键时,必须同时重写equals()和hashcode()方法。
3. hashcode()方法的编写步骤
4. HashMap的性能因子
几个术语:
(1)容量:表中的桶位数
(2)初始容量:表在创建时所拥有的桶位数。可以在HashMap和HashSet的构造器中指定初始容量。
(3)尺寸:表中当前存储的项数。
(4)负载因子:尺寸/容量。
HashMap和HashSet都有能指定负载因子的构造器,表示当负载情况达到该负载因子的水平时,容器将自动增加其容量(桶位数),实现方式是使容量大致加倍,并重新将现有对象分布到新的桶位集中(再散列)。
HashMap使用的默认负载因子是0.75。
5. 快速报错(fail-fast)
Java容器有一种保护机制,能够防止多个进程同时修改同一个容器的内容。Java容器类类库采用快速报错(fail-fast)机制,它会探查容器上的任何除了你的进程所进行的操作以外的所有变化,一旦它发现其他进程修改了容器,就会立刻抛出ConcurrentModificationException异常。这就是“快速报错”的意思——即,不是使用复杂的算法在事后来检查问题。
ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet都使用了可以避免ConcurrentModificationException的技术。
6. 持有引用
如果想继续持有某个对象的引用,希望以后还能够访问到该对象,但是也希望能够允许GC释放它,这时候就应该使用Reference对象。这样,你就可以继续使用该对象,而在内存消耗殆尽的时候又允许释放该对象。
以Reference对象作为你和普通引用之间的媒介(代理),另外,一定不能有普通引用指向那个对象,这样就能达到上述目的。(普通引用指的是没有经过Reference对象包装过的引用。)如果GC发现某个对象通过普通引用是可获得的,该对象就不会被释放。
[这有点类似于C++中的shared_ptr的角色,并且创建Reference对象的时候也有点类似于RAAI。]
A a = new A(); //a引用(普通引用)的对象不能被回收
Reference b = new Reference(new A()); //b应用的对象可以被回收,因为这个对象(往往是一大对象)一出生就被包裹了,没其他普通引用指向它,可以被回收
SoftReference、WeakReference、PhantomReference有强到弱排列,对应不同级别的“可获得性”。
第十八章 Java I/O系统
1. InputStream
此抽象类是表示字节输入流的所有类的超类。
[结合linux下C语言中的文件流指针struct FILE来理解就好了。在Linux下一切IO设备都是文件,所以这样的一个结构体表示了系统中各种各样的数据源,但在Java中具体的各种数据源由InputStream的子类来表示,比如AudioInputStream, ByteArrayInputStream, FileInputStream, PipedInputStream,SequenceInputStream, StringBufferInputStream等。]
具体如下表:
2. OutputStream
与InputStream类似的理解。如下表
3. Java中的IO类与装饰器模式
Java IO类库的设计使用了装饰器模式。
先看看装饰器模式的UML图:(具体可参考维基百科)
java IO对应的UML图
FilterInputStream和FilterOutputStream起到的是抽象装饰者的角色,它们的子类是具体的装饰者。
如下表:
4. Reader和Writer
与面向字节IO的InputStream和OutputStream不同,Reader和Writer提供兼容Unicode与面向字符IO的功能。
设计Reader和Writer继承层次结构主要是为了国际化。因为InputStream和OutputStream仅支持8位字节流,并不能很好地处理16位的Unicode字符。
5. IO中的适配器类
(1)InputStreamReader:字节——>字符(2个字节)
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如: BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
(2)OutputStreamWriter:字符(2个字节)——>字节
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
【记忆误区纠正】:之前一直将OutputStreamWriter记成了是将字节编码成字符。可以这样来纠正记忆:
(1)从OutputStreamWriter的构造函数来看:
OutputStreamWriter需要一个OutputStream对象,所以从形式上看就感觉是将字节流转换成了字符流,实则不然。构造函数需要OutputStream只是因为OutputStreamWriter需要借助OutputStream来完成具体的输出操作。
(2)从函数调用关系上来看:OutputStreamWriter.writer(字符char) ——> OutputStream.write(字节byte)
调用OutputStreamWriter之后我们得到的是一个Writer,而Writer的write()方法的参数都是字符。可以想象我们调用OutputStreamWriter的write()函数写入的字符,最后还得转化成字节流由内部的OutputStream对象来具体负责写出。所以这个OutputStreamWriter 类实际上是将字符编码成字节。
6. Java中标准IO重定向
System类的如下静态方法:setErr()、setOut()和setIn()可重定向IO,这些函数的参数的都是字符流。
7. 进程控制
Java中涉及到进程控制的有两个类:Process 和 ProcessBuilder。后者用来创建操作系统进程,返回一个前者的实例。
8. Java NIO
思想类似于Linux下的IO复用的,具体参考《NIO 入门》
9. 对象序列化
(1)概念:java的对象序列化就是将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
(2)为什么需要对象序列化?
对象序列化的概念加入到语言中是为了支持两种主要特性。一是Java的RMI,当向远程对象发送消息时,需要通过对象序列化来传递参数和返回值。二是对JavaBean来说,对象序列化也是必须的。需要在设计阶段保存它的状态信息,程序启动后进行后期恢复。
(3)具体步骤:让待序列化类实现一个标记接口Serializable,那么这个类的对象就是可序列化的了。
[Think In Java]基础拾遗3 - 容器、I/O、NIO、序列化的更多相关文章
- Java基础拾遗(二)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358523冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...
- Java基础拾遗(一)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358391冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...
- JAVA基础(10)——IO、NIO
转载:http://blog.csdn.net/weitry/article/details/52964948 JAVA基础系列规划: JAVA基础(1)——基本概念 JAVA基础(2)——数据类型 ...
- [Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类
目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式 ...
- JAVA基础知识:容器
JDK所提供的容器都在java.util包里面,下面开始讨论的都是JDK1.4版本的,只讲述基本知识,不涉及泛型 容器API的类图结构如下图所示 Set:元素无顺序且不可重复 List:元素 ...
- JAVA基础拾遗-论线程池的线程粒度划分与深浅放置
摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...
- Java基础 -- 持有对象(容器)
一 容器的用途 如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构. 我们可以通过创建引用来持有对象,如 Class clazz; 也可以通过数组来持有多个对象,如 Class[] ...
- [Think In Java]基础拾遗4 - 并发
第21章节 并发 1. 定义任务 任务:任务就是一个执行线程要执行的一段代码.(在C语言中就是函数指针指向的某个地址开始的一段代码) [记忆误区]:任务不是线程,线程是用来执行任务的.即任务由线程驱动 ...
- [Think In Java]基础拾遗2 - 多态、反射、异常、字符串
目录 第八章 多态第十四章 类型信息第十二章 通过异常处理错误第十三章 字符串 第八章 多态 1. 前期绑定 & 后期绑定 绑定是指将方法调用同一个方法主体关联起来的这么一个过程.如果在程序执 ...
随机推荐
- iOS 字典与JSON相互转换
iOS 字典与JSON相互转换 首先简单说一下为什么会写这种幼稚的文章. 现在的网络请求几乎都是AFN完成的,AFN也为我们写了了JSON转换字典的方法,但是不要忘记后台是一个很爱用JSON的人群,H ...
- Openstack api 学习文档 & restclient使用文档
Openstack api 学习文档 & restclient使用文档 转载请注明http://www.cnblogs.com/juandx/p/4943409.html 这篇文档总结一下我初 ...
- IndexOf、IndexOfAny 、Remove
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Microsoft SQL Server 2005 Service fails to start
今天碰到一雷死人的事情,在Windows Server 2012 R2上安装SQL SERVER 2005标准版过程中一直遇到"The SQL Server service failed t ...
- SQLSERVER自动定时(手动)备份工具
最近项目需要,写了一个小工具软件: 1.实时显示监控 2.可多选择备份数据库 3.按每天定时备份 4.备份文件自动压缩 5.删除之前备份文件 直接上图 1.备份监控界面: 2.数据库设置: 附工具下载 ...
- nodejs中stream相关资料
nodejs中流(stream)的理解 nodejs stream 手册完整中文版本 nodejs stream详细使用介绍
- win7升win10,初体验
跟宿舍哥们聊着聊着,聊到最近发布正式版的win10,听网上各种评论,吐槽,撒花的,想想,倒不如自己升级一下看看,反正不喜欢还可以还原.于是就开始了win10的初体验了,像之前装黑苹果双系统一样的兴奋, ...
- 我也来谈一谈c++模板(一)
c++中程序员使用模板能够写出与类型无关的代码,提高源代码重用,使用合适,大大提高了开发效率.此前,可以使用宏实现模板的功能,但是模板更加安全.清晰.在编写模板相关的代码是我们用到两个关键词:temp ...
- HashMap实现原理分析(转)
文章转自:http://blog.csdn.net/vking_wang/article/details/14166593 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但 ...
- OpenStack 企业私有云的若干需求(6):大规模扩展性支持
本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...