Java编程思想读书笔记——持有对象
来源:互联网 发布:广告算法工程师招聘 编辑:程序博客网 时间:2024/05/17 17:41
第十一章 持有对象
集合类:对象类型为List、Set、Queue和Map的类型。
11.1 泛型和类型安全的容器
使用预定义的泛型容器可以保存特定类型的对象,无论存取都不必关心类型转换。
该类型的子类对象也可以通过向上转型,存入到泛型容器中。
11.2 基本概念
Java容器类可以划分成两类:Collection与Map
1) Collection:一个独立元素的队列,这些元素都服从一条或多条规则。这一类又可以分为List、Set和Queue三个分类。
2) Map:一组成对的键值对对象,允许使用键查找值,也被称为字典或者关联数组。
通常情况下,在创建一个具体类对象时,会将其向上转型成为对应的接口,如:
List<Apple> apples = new ArrayList<>();List<Apple> apples2 = new LinkedList<>();
但是如果需要使用到具体类的特有方法时,就无需向上转型,直接创建具体类对象即可。
Collection接口概括了序列的概念,而序列是一种存放一组对象的方式。该接口有add()方法,表示将一个新元素放置到Collection中。
11.3 添加一组元素
创建Collection对象的方式:
1) 直接创建实现Collection接口的具体类对象,如ArrayList等;
a) 可以不接受参数,然后使用for循环逐个元素添加,也可以使用addAll()方法,将一组元素直接添加;b) 可以接受一个Collection对象作为参数,将该Collection对象的中所有元素存入新创建的Collection对象中。
2) 使用其他方法
a) 使用Arrays.asList(),该方法接受一个数组或者可变参数列表,并将之转换为List对象,需要注意的是,此种方式获得的List对象,由于底层实现仍然是数组,在添加或者删除元素时会出现UnsupportedOperationException异常。b) 使用Collections.addAll(),这一方法可以接收一个Collection对象、一个数组或者是可变参数列表作为参数,得到新的Collection对象;c) 使用Collection.addAll(),这一方法与上一种不同的是,它只能接受Collection对象作为参数,灵活性受到限制。
package com.mzm.chapter11;import java.util.*;/** * */public class AddingGroups { public static void main(String[] args){ Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); Integer[] moreInts = {6, 7, 8, 9, 10}; collection.addAll(Arrays.asList(moreInts)); Collections.addAll(collection, 11, 12, 13, 14, 15); Collections.addAll(collection, moreInts); List<Integer> list = Arrays.asList(16, 17, 18, 19, 20); list.set(1, 99); //产生UnsupportedOperationException //list.add(21); }}
之后的显示类型参数说明可能在之后的JDK版本中被修正了,没有书中说的运行结果。
10.4 容器的打印
Collection的toString()方法,以”[“开头,以”]”结尾,每个元素之间用”,”分隔;
Map的toString()方法,以”[“开头,以”]”结尾,每一对键值对之间,以”,”分隔,针对每一对键值对,键在前,值在后,中间使用”=”分隔。
10.5 List
addAll(int index, List<T> subList):在List的索引为index的位置,插入subList的所有元素;contains(T t):判断某个对象是否在List中;remove(T t):移除某个对象;remove(int index):移除List中索引为index的元素;removeAll():移除List中的全部元素;indexOf(T t):获取某个对象在List中的索引;add(int index, T t):在List中间插入元素,该操作消耗性能;subList(int startIndex, int endIndex):获取子List,包头不包尾,本质是创建一个新的List;containsAll(List<T> subList):List中是否包含subList中的全部元素;retainAll(List<T> otherList):List与otherList的交集,注意该操作不创建新的List,而是在原来的List上,将不在otherList中的元素删除;set(int index, T t):将List中索引为index的元素设置为t;isEmpty():判断List长度是否为0;clear():将List的所有元素清空;toArray():将List转换为数组,注意是返回Object数组;toArray(T list.get(i)):将List转换为数组,但返回的是类型与List的类型参数相同的数组;
11.6 迭代器
不考虑容器类型,对容器插入元素并将它们再次取回。
迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员无需关心该序列的底层实现。
迭代器也被称为轻量级对象,因为其创建代价小。
Java中的Iterator,它只能单向移动,具有如下方法:
iterator():返回一个Iterator对象,它将准备好返回序列的第一个元素;next():返回序列的下一个元素;hasNext():判断序列是否含有下一个元素;remove():将迭代器新近返回的元素删除;
迭代器将遍历序列的操作与序列底层的结构分离,统一了对容器的访问方式。
11.6.1 ListIterator
ListIterator是Iterator的一个子类,只能用于各种List的访问。ListIterator可以双向移动,可以产生当前位置的前一个和后一个元素的索引,并且可以使用set()方法,将最近访问过的元素进行替换。此外,还可以通过listIterator(int index)的方法,获得一个一开始就指向index位置的ListIterator。
11.7 LinkedList
LinkedList的增删为O(1),对元素的随机访问为O(n);ArrayList的增删为O(n),对元素的随机访问为O(1)。
getFirst()/element()/peek():获取第一个元素,poll()在列表为空时返回null,另外两个抛出NoSuchElementException异常; removeFirst()/remove()/poll():移除并返回第一个元素,差异与上面类似;addFirst()/add()/offer()/addLast():将某个元素添加的末尾;removeLast():移除并返回最后一个元素。
11.8 Stack
栈是指先进后出的容器,也被称为叠加栈,最典型的例子是自助餐托盘。
可以使用LinkedList来实现:
package com.mzm.chapter11;import java.util.LinkedList;/** * */public class Stack<T> { private LinkedList<T> storage = new LinkedList<>(); public void push(T v){ storage.addFirst(v); } public T peek(){ return storage.getFirst(); } public T pop(){ return storage.removeFirst(); } public boolean empty(){ return storage.isEmpty(); } public String toString(){ return storage.toString(); }}
11.9 Set
Set不保存重复元素。
查找是Set最重要的操作,一般是使用HashSet。
HashSet、TreeSet和LinkedHashSet的区别在于,HashSet使用散列函数来维护元素的顺序,TreeSet是将元素存储在红黑树数据结构中,LinkedHashSet使用链表来维护元素的插入顺序。
方法包括:add()、addAll()、contains()、addAll()、containsAll()、remove()、removeAll()。
11.10 Map
Map是将对象映射到另一个对象。
11.11 Queue
队列是一个先进先出的容器。
LinkedList提供了方法以支持队列的行为,并且实现了Queue接口,所以可以使用Queue引用指向LinkedList对象。
11.11.1 PriorityQueue
队列规则:在给定一组队列中的元素的情况下,确定下一个弹出队列的元素的规则。
先进先出声明的是下一个元素应该是等待时间最长的元素。
优先级队列声明下一个弹出元素是最需要的元素(具有最高优先级)。
PriorityQueue在调用offer()方法插入元素时,默认是根据自然顺序排列的,可以传入自定义的Comparator来修改顺序。
package com.mzm.chapter11;import java.util.*;/** * Created by 蒙卓明 on 2017/10/14. */public class PriorityQueueDemo { public static void main(String[] args){ //默认是升序排列 PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(); Random rand = new Random(47); for(int i = 0; i < 10; i++){ priorityQueue.offer(rand.nextInt(i + 10)); } QueueDemo.printQ(priorityQueue); List<Integer> ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2, 3, 9, 14, 18, 21, 23, 25); priorityQueue = new PriorityQueue<>(ints); QueueDemo.printQ(priorityQueue); //指定降序 priorityQueue = new PriorityQueue<>(ints.size(), Collections.reverseOrder()); priorityQueue.addAll(ints); QueueDemo.printQ(priorityQueue); String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION"; List<String> strings = Arrays.asList(fact.split("")); PriorityQueue<String> stringPQ = new PriorityQueue<>(strings); QueueDemo.printQ(stringPQ); //指定降序 stringPQ = new PriorityQueue<>(strings.size(), Collections.reverseOrder()); stringPQ.addAll(strings); QueueDemo.printQ(stringPQ); Set<Character> charSet = new HashSet<>(); for(char c : fact.toCharArray()){ charSet.add(c); } PriorityQueue<Character> characterPQ = new PriorityQueue<>(); QueueDemo.printQ(characterPQ); }}
11.12 Collection和Iterator
如果要针对所有Collection类型提供共同的方法,最好是通过迭代器的方式。实现Collection接口,需要实现该接口的所有方法,较为麻烦,虽然AbstractCollection提供了Collection的默认实现,即使是继承该类,也必须提供迭代器的实现,何况已经继承了其他类的情况,所以最好是使用迭代器。
package com.mzm.chapter11;import java.util.*;/** * Iterator比Collection要好一些 * */public class InterfaceVsIterator { public static void display(Iterator<Pet> it){ while(it.hasNext()){ Pet p = it.next(); System.out.print(p.id() + ":" + p + " "); } System.out.println(); } public static void display(Collection<Pet> pets){ for(Pet p : pets){ System.out.print(p.id() + ":" + p + " "); } System.out.println(); } public static void main(String[] args){ List<Pet> petList = Pet.arrayList(8); Set<Pet> petSet = new HashSet<>(petList); Map<String, Pet> petMap = new LinkedHashMap<>(); String[] names = {"Ralph", "Eric", "Robin", "Lacey", "Britney", "Sam", "Spot", "Fluffy"}; for(int i = 0; i < 8; i++){ petMap.put(names[i], petList.get(i)); } display(petList); display(petSet); display(petList.iterator()); display(petSet.iterator()); System.out.println(petMap); System.out.println(petMap.keySet()); display(petMap.values()); display(petMap.values().iterator()); }}
package com.mzm.chapter11;import java.util.AbstractCollection;import java.util.Iterator;/** * AbstractCollection提供了Collection的默认实现,但即使继承该类,也同样要实现iterator()方法来提供迭代器 * 不如直接使用迭代器 * */public class CollectionSequence extends AbstractCollection<Pet> { private Pet[] pets = Pet.arrayList(8).toArray(new Pet[0]); @Override public Iterator<Pet> iterator() { return new Iterator<Pet>() { private int index = 0; @Override public boolean hasNext() { return index < pets.length; } @Override public Pet next() { return pets[index++]; } public void remove(){ throw new UnsupportedOperationException(); } }; } @Override public int size() { return pets.length; } public static void main(String[] args){ CollectionSequence c = new CollectionSequence(); InterfaceVsIterator.display(c); InterfaceVsIterator.display(c.iterator()); }}
package com.mzm.chapter11;import java.util.Iterator;/** * 当这个类继承了其他类时,不能再继承AbstractCollection了 * */public class NonCollectionSequence extends PetSequence{ public Iterator<Pet> iterator(){ return new Iterator<Pet>() { private int index = 0; @Override public boolean hasNext() { return index < pets.length; } @Override public Pet next() { return pets[index++]; } public void remove(){ throw new UnsupportedOperationException(); } }; }}class PetSequence{ protected Pet[] pets = Pet.arrayList(8).toArray(new Pet[0]);}
11.13 Foreach与迭代器
所有的Collection都能使用foreach语法遍历,因为其实现了Iterable接口,该接口包含一个能够产生Iterator的iterator()的方法。
注意数组没有实现Iterable接口。
11.13.1 适配器方法惯用法
如果需要在foreach中进行反序遍历,可以使用适配器设计模式。
package com.mzm.chapter11;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Iterator;/** * 使用适配器设计模式在foreach中添加反向遍历 * */public class AdapterMethodIdiom { public static void main(String[] args){ ReversibleArrayList<String> ral = new ReversibleArrayList<>(Arrays.asList("To be or not to be".split(" "))); //正向遍历 for(String s : ral){ System.out.print(s + " "); } System.out.println(); //反向遍历 for(String s : ral.reverse()){ System.out.print(s + " "); } }}class ReversibleArrayList<T> extends ArrayList<T>{ public ReversibleArrayList(Collection<T> c){ super(c); } public Iterable<T> reverse(){ return new Iterable<T>() { @Override public Iterator<T> iterator() { return new Iterator<T>() { int current = size() - 1; @Override public boolean hasNext() { return current > -1; } @Override public T next() { return get(current--); } public void remove(){ throw new UnsupportedOperationException(); } }; } }; }}
- Java编程思想读书笔记——持有对象
- Java编程思想——持有对象
- Java编程思想第四版读书笔记——第十一章 持有对象
- java编程思想读书笔记 第十一章 持有对象(中)
- java编程思想读书笔记 第十一章 持有对象(下)
- java编程思想读书笔记 第十一章 持有对象(总结)
- java编程思想读书笔记----第十一章 持有对象
- Java编程思想——持有对象(11)
- Java编程思想(八) —— 持有对象(上)
- Java编程思想(九) —— 持有对象(下)
- java编程思想-持有对象
- 《Java编程思想-持有对象》
- 《读java编程思想》 持有对象(11)
- <Java编程思想>持有对象(笔记)
- JAVA编程思想-第十一章 持有对象
- 11持有对象-Java编程思想
- 11持有对象-Java编程思想
- 《java编程思想》第十一章 持有对象
- WebServer服务器原理(例子)
- Android 6.0 运行时权限处理 二维码开发
- QTcpSocket 通讯 ( 服务器、客户端、封包、解包 )
- java开发/10.1-10.3/邓聪
- 微信公众号title替换
- Java编程思想读书笔记——持有对象
- IntelliJ 添加JRebel 实现 Tomcat热部署
- POJ 2992 Divisors(求组合数因子个数)
- C++判断出栈顺序
- C++构造函数简述
- 一个合格的程序员应该读过哪些书
- javaWeb之jsp转化servlet
- 众多回文问题
- WinMIPS64下实现冒泡排序(函数调用)