目录

第十一章 持有对象
第十七章 容器深入研究
第十八章 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、序列化的更多相关文章

  1. Java基础拾遗(二)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358523冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  2. Java基础拾遗(一)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76358391冷血之心的博客) 马上就要秋招了,新的一轮笔试面试马上 ...

  3. JAVA基础(10)——IO、NIO

    转载:http://blog.csdn.net/weitry/article/details/52964948 JAVA基础系列规划: JAVA基础(1)——基本概念 JAVA基础(2)——数据类型 ...

  4. [Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类

    目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式 ...

  5. JAVA基础知识:容器

    JDK所提供的容器都在java.util包里面,下面开始讨论的都是JDK1.4版本的,只讲述基本知识,不涉及泛型 容器API的类图结构如下图所示 Set:元素无顺序且不可重复      List:元素 ...

  6. JAVA基础拾遗-论线程池的线程粒度划分与深浅放置

    摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...

  7. Java基础 -- 持有对象(容器)

    一 容器的用途 如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构. 我们可以通过创建引用来持有对象,如 Class clazz; 也可以通过数组来持有多个对象,如 Class[] ...

  8. [Think In Java]基础拾遗4 - 并发

    第21章节 并发 1. 定义任务 任务:任务就是一个执行线程要执行的一段代码.(在C语言中就是函数指针指向的某个地址开始的一段代码) [记忆误区]:任务不是线程,线程是用来执行任务的.即任务由线程驱动 ...

  9. [Think In Java]基础拾遗2 - 多态、反射、异常、字符串

    目录 第八章 多态第十四章 类型信息第十二章 通过异常处理错误第十三章 字符串 第八章 多态 1. 前期绑定 & 后期绑定 绑定是指将方法调用同一个方法主体关联起来的这么一个过程.如果在程序执 ...

随机推荐

  1. iOS 字典与JSON相互转换

    iOS 字典与JSON相互转换 首先简单说一下为什么会写这种幼稚的文章. 现在的网络请求几乎都是AFN完成的,AFN也为我们写了了JSON转换字典的方法,但是不要忘记后台是一个很爱用JSON的人群,H ...

  2. Openstack api 学习文档 & restclient使用文档

    Openstack api 学习文档 & restclient使用文档 转载请注明http://www.cnblogs.com/juandx/p/4943409.html 这篇文档总结一下我初 ...

  3. IndexOf、IndexOfAny 、Remove

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. Microsoft SQL Server 2005 Service fails to start

    今天碰到一雷死人的事情,在Windows Server 2012 R2上安装SQL SERVER 2005标准版过程中一直遇到"The SQL Server service failed t ...

  5. SQLSERVER自动定时(手动)备份工具

    最近项目需要,写了一个小工具软件: 1.实时显示监控 2.可多选择备份数据库 3.按每天定时备份 4.备份文件自动压缩 5.删除之前备份文件 直接上图 1.备份监控界面: 2.数据库设置: 附工具下载 ...

  6. nodejs中stream相关资料

    nodejs中流(stream)的理解 nodejs stream 手册完整中文版本 nodejs stream详细使用介绍

  7. win7升win10,初体验

    跟宿舍哥们聊着聊着,聊到最近发布正式版的win10,听网上各种评论,吐槽,撒花的,想想,倒不如自己升级一下看看,反正不喜欢还可以还原.于是就开始了win10的初体验了,像之前装黑苹果双系统一样的兴奋, ...

  8. 我也来谈一谈c++模板(一)

    c++中程序员使用模板能够写出与类型无关的代码,提高源代码重用,使用合适,大大提高了开发效率.此前,可以使用宏实现模板的功能,但是模板更加安全.清晰.在编写模板相关的代码是我们用到两个关键词:temp ...

  9. HashMap实现原理分析(转)

    文章转自:http://blog.csdn.net/vking_wang/article/details/14166593 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但 ...

  10. OpenStack 企业私有云的若干需求(6):大规模扩展性支持

    本系列会介绍OpenStack 企业私有云的几个需求: 自动扩展(Auto-scaling)支持 多租户和租户隔离 (multi-tenancy and tenancy isolation) 混合云( ...