《Java编程思想》第四版读书笔记 第十一章 持有对象

11.1java

在第一个例子中使用了@SuppressWarnings注解。它的做用是抑制编译器产生的告警信息。设计模式

(1)用于抑制一个类型的警告:数组

@SuppressWarnings("unchecked")函数

(2)用于抑制多个类型的警告:测试

@SuppressWarnings(value = {"unchecked", "rawtypes"})优化

(3)用于抑制多有类型的警告:编码

@SuppressWarnings("all")spa

该注解目标为类、字段、函数、函数形参、构造函数和函数的局部变量。建议注解声明在最接近告警发生的位置。操作系统

javac -Xlint 用于在编译程序的过程当中进行更细节的额外检查。翻译

javac带有-X表示非标准选项(不带-X天然是标准选项了),表示当前版本支持,将来不必定支持的选项。经过javac -X可查看当前版本支持的非标准选项。

11.2

Java 容器划分红两个不一样的概念:

(1)Collection。一个独立元素的序列,这些元素都服从一些规则。例如,List必须按顺序插入,Set不能有重复的元素,Queue是队列;

(2)Map。一组键值对对象,容许使用键来查找值。

11.3

本小节主要介绍了四种获得列表的方法:

(1)Collection的构造函数能够接受另外一个Collection对象,用它来初始化自身;

(2)Arrays.asList()方法的参数能够是数组或变长参数,返回的是List对象,可是在这种状况下,其底层表示的是数组,所以不能调整尺寸,当调用它的add()方法和remove()(此处书中写的是delete()方法,应该是笔误)方法时会抛出Unsupported Operation异常;

(3)Collections.addAll()方法的参数是一个Collection对象、数组或变长参数,将元素添加到Collection对象中;

(4)Collection.addAll()(注意这里是Collection不是Collections)只能接口另外一个Collection对象做为参数,这种方法不如(2)和(3)灵活,可是这种方法速度很快,当复合条件时它为首选。

本小节的最后,做者举例说明了Arrays.asList()可能会遇到的问题和解决的方法。当将Light和Heavy类型的对象做为参数传入Arrays.asList()方法中时,编译器会认为方法返回的类型是List,将其赋值给一个List的引用就会报错,解决方法是给Arrays.asList()方法添加显示类型Arrays.asList()。

通过编码测试这个问题在1.8中获得了解决,可是1.7以前的版本依旧存在这个问题。

11.4

若是想要打印数组的内容,必须将其做为参数传递给Arrrays.toString()方法,可是容器不须要相似的帮助,它的toString()直接能够打印出容器的内容。

Collection容器主要包括:

(1)List,它以特定的顺序保存一组元素。ArrayList和LinkedList是List的两个主要类型。ArrayList长于随机访问元素,可是在中间插入和移除元素较慢。LinkedList优化了顺序访问,而且在List中间进行插入和删除操做代价较低,可是随机访问较慢,而且它的特性比ArrayList更大。

(2)Set,它的元素不能重复。HashSet、TreeSet和LinkedHashSet是主要的Set类型。经过将它们的内容打印出来能够看出,它们实现存储元素的方式不一样。HashSet使用较复杂的存储方法以提供最快的获取元素方式;TreeSet按照比较结果的升序保存对象;LinkedHashSet按照添加的顺序保存对象。

(3)Queue,它只容许在一端插入对象,在另外一端移除对象。

HashMap、TreeMap和LinkedHashMap是Map的三种主要类型,主要区别于 HashSet、TreeSet和LinkedHashSet相同。

11.5

例子中总结了一些List的方法:

可使用contains()方法来肯定某个对象是否在列表中,若是想移除一个对象,则能够将这个对象的引用传递给remove()方法,无此对象会致使删除失败,方法返回false。若是有一个对象的引用,可使用indexOf()方法来发现对象在List中的索引号,无此对象返回-1。

注意:肯定一个元素是否属于List、发现某个元素的索引以及从List中移除一个元素,会用到equals()方法。因此List的这些行为会根据持有对象的equals()行为不一样有所变化。也可使用索引来移除List中的一个元素,这样就不用担忧equals()方法。

能够在List中间插入,ArrayList中间插入是很昂贵的,而LinkedList中间插入是很廉价的。

containsAll()判断不在意顺序。

shuffle()方法的做用是随机打乱原来的元素顺序(洗牌)。

retainAll()仅在List中保留指定collection中所包含的元素。

set()方法替换掉指定索引位置的元素。

addAll()不指定位置将添加到list最后,若是指定位置能够插入到List中间。

toArray()方法将Collection转换为数组。无参数版本返回的是Object数组,有参数的版本能够向其传递目标类型的数组,那么它将产生指定类型的数组(而不是Object数组)。若是参数数组过小,存放不下目标类型的数据,那么它将建立合适尺寸的数组。

11.6

迭代器一般被称为轻量级对象,建立它的代价很是小。

Iterator的做用(它只能单向移动):

(1)使用容器的iterator()方法要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素;

(2)使用next()得到序列中的下一个元素;

(3)使用hasNext()检测序列中是否还有元素;

(4)使用remove()将迭代器新近返回的元素删除。这里须要注意,迭代器真的能够删除容器里的元素,可是注意调用remove()以前必须调用next()方法。remove()方法是一个可选的方法,即不是全部的Iterator实现都必须实现该方法。(为何它是可选的?我看API remove()方法若是迭代器不支持 remove 操做会抛出 UnsupportedOperationException  。

迭代器实际上是一种设计模式,使用它能够没必要知道容器的确切类型。这样就可以将遍历序列的操做与序列底层的结构分离

ListIterator是Iterator的子类型,它更强大,可是它只能用于各类List类的访问。它能够双向移动。

nextIndex()对 next 的后续调用所返回元素的索引。(若是列表迭代器在列表的结尾,则返回列表的大小);

previousIndex()返回对 previous 的后续调用所返回元素的索引。(若是列表迭代器在列表的开始,则返回 -1);

可使用set()方法替换访问过的最后一个元素;

调用listIterator()方法产生一个指向List开始处的ListIterator,也能够调用listIterator(int n)方法建立一个开始就指向 索引为n的元素处的ListIterator。

11.7

LinkedList在实现了基本的List接口的功能之上还添加了可使其用做栈、队列或双端队列的方法。

有些方法并无差异、有些只有细微的差异,它们有不一样的名字主要是由于这些名字在特定的环境中更加 合适。例如:

getFirst()、element()和peek()都返回列表的第一个元素且不删除它们,若是列表为空前两个方法会抛出NoSuchElmentException,peek()方法则会返回null;

removeFirst()、remove()和poll()方法都是移除并返回列表的头,若是列表为空前两个会抛出NoSuchElementException,poll()方法会返回null;

addFirst()与add()和addLast()相同,都将某个元素 插入到列表的尾部;

removeLast()移除并返回列表的最后一个元素;

offer()将指定元素添加的列表的末尾。

练习13上一段有句话翻译有误,原话为“若是你浏览一下Queue接口就会发现,它在LinkedList的基础上添加了element()、offer()、peek()、poll()和remove()方法,以使其能够成为一个Queue的实现。”翻了一下英文版,认为应该翻译为:“若是你浏览一下Queue接口就会发现,element()、offer()、peek()、poll()和remove()方法被添加到LinkedList类中使其成为一个Queue接口的实现。

11.8

做者使用代理用LinkedList实现了一个栈,这里使用代理而不是继承LinkedList是由于LinkedList还有许多与栈无关的方法,使用代理能够屏蔽掉。一个栈须要的方法主要有push(T t)入栈、poll()出栈和peek()返回栈顶元素但不删除,另外还须要有一个empty()方法判断栈是否为空。

Java在早期版本中就已经有了栈java.util.Stack,可是因为设计糟糕,如今已经不推荐使用了,还有Vector、Dictionary等。

11.9

TreeSet的构造函数容许传入一个比较器(Comparator) 做为参数用于给元素排序

在最后一个例子中做者为字符串不区分大小写排序传入了String.CASE_INSENSITIVE_ORDER比较器。

11.10

对象能够返回它的键的Set——keySet(),返回值的Collection——values(),返回键值对的Set——entrySet()。

11.11

若是想使用队列,能够建立LinkedList对象并向上转型为Queue,这样Queue接口窄化了LinkedList的访问权限。

offer()方法在容许的状况下将元素插入到队尾,peek()和element()在不删除元素的状况下返回队头,若是队列为空前者返回Null,然后者抛出NoSuchElementException异常。poll()和remove()方法返回队头并删除元素,队列为空时前者返回Null,后者抛出异常。

Java 1.5添加了PriorityQueue类,在这个队列中,不是根据插入的时间来弹出元素,而是根据元素的优先级,优先级高的先弹出。当用offer()向PriorityQueue插入对象后,它会在队列中根据天然顺序进行排序,能够向PriorityQueue传入自定义的Comparator来改变默认的顺序。

练习29让咱们建立一个继承自Object的类,而后把这个类的实例添加到PriorityQueue队列中,这样会抛出异常,由于这个类没有实现Comparable接口,PriorityQueue没有办法判断元素的优先级。

11.12

首先介绍了AbstractCollection抽象类,它实现了Collection接口,只有iterator()和size()方法是抽象方法,继承时须要实现。另外须要注意的是AbstractCollection的add()方法虽然被实现了,可是函数里仅有一句代码——抛出UnSupportedOperationException异常。因此继承AbstractCollection时还要覆盖add()方法。

11.13

Java 1.5添加了Iterable接口,它的iterator()方法返回一个迭代器,注意到Collection接口也继承了Iterable接口。实现Iterable接口的类均可以应用在foreach语句中,同时数组也能够应用于foreach语句,可是注意数组并无实现Iterable接口。

System.getEnv()方法返回操做系统的环境变量。

例子中使用了设计模式中的适配器模式,它的主要功能是将一个类的接口转换成客户但愿的另一个接口。Adapter模式使得本来因为接口不兼容而不能一块儿工做的那些类能够在一块儿工做。

例子中着重提到了Arrays.asList()方法,若是修改方法返回的List,那么做为参数传入的数组也将会被修改,此种状况容易被忽略。

11.14

新程序中不该该再使用已通过时的Vector、Hashtable和Stack。

下图是容器相关的接口和类之间的关系:

总结起来共有四种容器:List、Set、Queue和Map。每一种各有两三个实现。经常使用的在图中用粗线框表示,虚线框表示接口,实线框表示类。空心虚线箭头接口或者类实现了上层接口,实心虚线箭头表示某个类能够生成箭头所指向的类。

相关文章
相关标签/搜索