Java编程思想---第十一章 持有对象(中)
第十一章 持有对象(中)
11.6.1 ListItrator
ListIterator是一个更加强大的Iterator的子类型,它只能用于各种List类的访问,尽管Iterator只能向前移动,但是ListIterator可以双向移动它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的指引,并且可以使用set()方法替换它访问过的最后一个元素。你可以通过调用listIterator()方法产生一个指向List()开始处的ListIterator。
11.7 LinkedList
LinkedList也想ArrayList一样实现了基本的List接口,但是它执行某些操作时比ArrayList更高效,但在随机访问操作方面却要逊色一些。LinkedList还添加了可以使其用作栈、队列或双端队列的方法,这些方法中有些彼此之间只是名称有些差异,以使得这些名字在特定用法的上下文环境中更加适用,特别是在Queue中。
11.8 Stack
栈通常是指后进先出的容器,有时栈也被称为叠加站,因为最后压入栈的元素,第一个弹出栈,经常用来类比栈的食物是装有弹簧的储放器中的自助餐托盘,最后装入的托盘总是最先拿出使用的。LinkedList具有能够直接实现栈的所有功能的方法,因此可以直接将LinkedList作为栈使用。不过有时一个真正的栈更能把事情讲清楚:
import java.util.LinkedList; public class Stack<T> { private LinkedList<T> storage = new LinkedList<T>(); 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(); } }
这里通常使用泛型,引入了在栈的类定义中最简单的可行示例,类名之后的<T>搞死编译器这将是一个参数化类型,而其中的参数,即在类被使用时将会被实际类型替换的参数,也就是T。大体上这个类是在声明我们在定义一个可以持有T类型对象。
如果你只需要栈的行为,这里使用继承就不太合适了,因为这样会产生具有LinkedList的其他所有方法的类,下面演示的这个新的Stack类:
public class StackTest { public static void main(String[] args) { Stack<String> stack = new Stack<String>(); for(String s : "My dog has fleas".split(" ")) stack.push(s); while (!stack.empty()) System.out.print(stack.pop() + " "); } }
如果你想在自己的代码中使用这个Stack类,当你在创建其示例时,就需要完整指定包名,或者更改这个类的名称,否则可能与java.util包中的Stack发生冲突。
11.9 Set
Set不保存重复的元素,如果你试图将相同对象的多个实例添加到Set中,那么它就会阻止这种重复现象,Set中最常被使用的是测试归属性,你可以很容易询问某个对象是否在某个Set中,正因如此查找成为了Set中最重要的操作,因此你通常都会选择一个HashSet的实现,它专门对快速查找进行了优化。
Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List,实际上Set就是Collection,只是行为不同,Set是基于对象的值来确定归属性的。
下面是使用存放Integer对象的HashSet示例:
import java.util.*; public class SetOfInteger { public static void main(String[] args) { Random random = new Random(47); Set<Integer> intset = new HashSet<Integer>(); for(int i = 0; i<10000; i++) intset.add(random.nextInt(30)); System.out.println(intset); } }
输出结果为:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
11.10 Map
将对象映射到其他对象的能力是一种解决编程问题的杀手锏,例如考虑一个程序,他将用来检查Java的Random类的随机性,理想状态下,Random可以将产生理想的数字分布,但要想测它,则需要生成大量的随机数,并对落入各种不同范围的数字进行计数,Map可以很容易地解决该问题。
import java.util.*;
public class Statistics { public static void main(String[] args) { Random random = new Random(47); Map<Integer,Integer> m = new HashMap<Integer, Integer>(); for(int i = 0; i<10000; i++){ int r = random.nextInt(20); Integer freq = m.get(r); m.put(r,freq == null ? 1 : freq + 1); } System.out.println(m); } }
在main()中,自动包装机制将随机生成的int转换为HashMap可以使用的Integer引用,如果键不在容器中,get()方法将返回null没否则get()方法将产生与该键相关联的Integer值,然后这个值递增。
11.11 Queue
队列是一个典型的先进先出的容器,即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是相同的,队列常被当做一种可靠的将对象从程序的某个区域传输到另一个区域的途径,队列在并发编程中特别重要。
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现,通过将LinkedList向上转型为Queue:
import java.util.*; public class QueueDemo { public static void printQ(Queue queue) { while (queue.peek() != null) System.out.print(queue.remove() + " "); System.out.println(); } public static void main(String[] args){ Queue<Integer> queue = new LinkedList<Integer>(); Random random = new Random(47); for(int i = 0; i<10; i++) queue.offer(random.nextInt(i + 10)); System.out.println(queue); Queue<Character> qc = new LinkedList<Character>(); for(char c : "Brontosaurus".toCharArray()) qc.offer(c); System.out.println(qc); } }
offer方法是与Queue相关的方法之一,它在允许的情况下,将一个元素插入到队尾,或者返回false,peek和element都将在不溢出的情况下返回队头,但是peek方法在队列为空时返回null,而element会抛出NoSuchElementException异常,poll和remove方法将移除并返回队头,但是poll在队列为空时返回null,而remove会抛出NoSuchElementException异常。
11.11.1 PriorityQueue
先进先出描述了最典型的队列规则,队列规则是指在给定一组队列中的元素的情况下,确定下一个弹出队列的元素的规则。先进先出声明的是下一个元素应该是等待时间最长的元素。优先级队列声明下一个弹出元素时最需要的元素。
当你在PriorityQueue上调用offer方法插入一个对象时买这个对象会在队列中被排除,默认的排序将使用对象在队列中的自然顺序,但是你可以通过提供自己的Comparator来修改这个顺序,PriorityQueue可以确保当你调用peek、poll、remove方法时,获取的元素将是队列中优先级最高的元素。
您的资助是我最大的动力!
金额随意,欢迎来赏!
因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【寓言i】!
联系或打赏博主【寓言i】!https://www.cnblogs.com/parable/