编程思想之——持有对象解惑

 当你指定了某个类型作为泛型参数时,你并不仅限于只能将该确切类型的对象放置到容器中。向上转型也可以像作用于其他类型一样作用于泛型。
package com.qihe;

import java.util.ArrayList;
import java.util.List;

class GrannySmith extends Apple
{
}

class Fuji extends Apple
{
}

class Braeburn extends Apple
{
}

public class GenericsAndUpcasting
{
public static void main(String[] args)
{
List<Apple> apples = new ArrayList<Apple>();
apples.add(new GrannySmith());
apples.add(new Fuji());
apples.add(new Braeburn());
for (Apple a : apples)
System.out.println(a);

}
}
因此,你可以将Apple的子类型添加到被指定为保存Apple对象的容器中。


 添加一组元素
package com.qihe;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class AddingGroups
{
public static void main(String args[])
{
Collection<Integer> collection = new ArrayList<Integer>(
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);
}
}

三种基本风格的Map:HashMap、TreeMap和LinkedHaspMap。与HashSet一样,HashMap也提供了最快的查找技术,也没有按照任何明显的顺序来保存其元素。TreeMap按照比较结果的升序保存键,而LinkedHashMap则按照插入顺序保存键,同时还保留了HaspMap 的查询速度。


 List
List承诺可以将元素维护在特定的序列中。
有两种类型的List:

1) 基本的ArrayList,它长于随机访问元素,但是在List的中间插入和移除元素时较慢。
2) LinkedList,它通过代价较低的在List中间进行的插入和删除操作,提供了优化的顺序访问。LinkedList在随机访问方面相对比较慢,但是它的特性较ArrayList更大。

 迭代器
Iterator
ListIterator:是一个更加强大的Iterator的子类型,它只能用于各种List的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。你可以通过调用
listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n 的元素的ListIterator,下面的示例演示了所有这些能力。


 LinkedList
LinkedList也像ArrayList一样实现了基本的List接口,但是它执行某些操作(在List的中间插入和移除)时比ArrayList更高效,但是在随机访问操作方面却要逊色一些。
LinkedList还添加了可以使其用作栈、队列或双端队列的方法。
这些方法中有些彼此之间只是名称有些差异,或者只存在些许差异,以使得这些名字在特定用法的上下环境中更加适用(特别是在Queue中)。例如,getFirst()和elements()完全样,它们都返回列表的头(第一个元素),而并不移除它,如果List为空,则抛出NoSuchElementException。peek()方法与这两个方式只是稍有差异,它在列表为空时返回null.
removeFirst()与remove()也是完全一样的,它们移除并返回列表的头,而在列表为空时抛出NoSuchElementException。poll()稍有差异,它在列表为空时返回null.
addFirst()与add()和addLast()相同,它们都将某个元素插入到列表的尾(端)部。
removeLast()移除并返回列表的最后一个元素。


 Stack
“栈”通常是指“后进先出”的容器。
LinkedList具有能够直接实现栈的所有功能的方法。因此可以直接将LinkedList作为栈使用。
不过,有时一个真正的“栈”更能把事情讲清楚:
package com.qihe;

import java.util.LinkedList;
import java.util.List;

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();
}
}


 Set
Set不保存重复的元素(至于如何判断元素相同则较为复杂,稍后便会看到)。你可以很容易地询问某个对象是否在某个Set中,正因如此,查找就成为了Set中最重要的操作。因此你通常都会 选择一个HashSet的实现,它专门对快速查找进行优化。
Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List,实际上Set就是Collection,只是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set是基于对象的值来确定归属性的。
HashSet所维护的顺序与TreeSet或LinkedHashSet都不同,因为它们的实现具有不同的元素存储方式。TreeSet将元素存储在红-黑树数据结构中,而HashSet使用的是散列函数。LinkedHashSet因为查询速度的原因也使用了散列,但看起来它使用了链表来维护元素的插入顺序。

如果你想对结果排序,一种方式是使用TreeSet来代替HashSet:

package com.qihe;

import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;

public class SortedSetOfInterger
{

public static void main(String[] args)
{
Random rand = new Random(47);
SortedSet<Integer> insert = new TreeSet<Integer>();
for (int i = 0; i < 1000; i++)
{
insert.add(rand.nextInt(20));

}
System.out.println(insert);

}
}

输出结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]


 Map
将对象映射到其他对象的能力是一种解决编程问题的杀手锏。例如,考虑一个程序,


 Queue
队列是一个典型的先进先出的容器。
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。通过将LinkedList向上转型为Queue,下面的示例使用了在Queue接口与Queue相关的方法。


package com.qihe;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

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 rand = new Random(47);
for (int i = 0; i < 10; i++)
queue.offer(rand.nextInt(i + 10));
printQ(queue);
Queue<Character> qc = new LinkedList<Character>();
for (char c : "Brontosaurus".toCharArray())
qc.offer(c);
printQ(qc);
}

}
输出结果:8 1 1 1 5 14 3 1 0 1
B r o n t o s a u r u s

注:offer()方法是与Queue相关的方法之一,它在允许的情况下,将一个元素插入到队尾,或者返回false,peek()他elements()都将在不移除的情况下返回队头。
但是peek()方法在队列为空时返回null,而elements()会抛出NoSuchElementException异常。poll()和remove()方法将移除并返回队头,但是poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。


 PriorityQueue
先进先出描述了最典型的队列规则。队列规则是指在给定一组队列中的元素的情况下,确定下一个弹出队列的元素的规则。先进先出声明的是下一个元素是等待时间最长的元素。
优先级队列声明下一个弹出元素是最需要的元素(具有最高的优先级)。例如,在飞机场,当飞机临近起飞时,这架飞机的乘客可以在办理登机手续时排到队头,如果构建了一个消息系统,某些消息比其他消息列重要,因而应该更快地得到处理,那么它们何时得到处理就与它们何时到达无关。PriorityQueue添加到JavaSe5中,是为了提供这种行为的一种自动实现 。
当你在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序。默认的排序将使用对象在队列中的自然顺序,但你可以通过提供自己的Comparator来修改这个顺序。PriorityQueue可以确保当你调用peek(),poll()和remove()方法时,获取的元素将是队列中优先级最高的元素。

让PriorityQueue与Integer、String和Character这样的内置类型一起工和易如反掌。在下面的示例中,第一个值集与前一个示例中的随机值相同,因此你可以看到它们的从PriorityQueue中弹出的顺序与前一个示例不同。

package com.qihe;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Random;
import java.util.Set;

public class PriorityQueueDemo
{
public static void main(String[] args)
{
PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>();
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<Integer>(ints);
QueueDemo.printQ(priorityQueue);

priorityQueue = new PriorityQueue<Integer>(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<String>(strings);
QueueDemo.printQ(stringPQ);

stringPQ = new PriorityQueue<String>(strings.size(),
Collections.reverseOrder());
stringPQ.addAll(strings);
QueueDemo.printQ(stringPQ);

Set<Character> charSet = new HashSet<Character>();
for (char c : fact.toCharArray())
charSet.add(c);
PriorityQueue<Character> characterPQ = new PriorityQueue<Character>(
charSet);
QueueDemo.printQ(characterPQ);
}
}

注:你可以看到,重复是充许的,最小的值拥有最高的优先级(如果是String,空格也可以算作值 ,并且比字母的优先级高)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值