【练习13-1(IGenQ.java、QueueFullException.java、QueueEmptyException.java、GenQueue.java、GenQDemo.java)】创建一个泛型队列
泛型带给程序设计的最大好处之一就是能够创建可靠、可重用的代码。如本章开头所述,许多算法不管使用的数据类型是什么、算法逻辑都是相同的。例如,队列的工作方式对于整数、字符串或File对象都是相同的。不必为每一种类型的对象分别创建独立的队列类,创建单个通用的解决方案就可以使用任何类型的对象。这样,设计、编码、测试和调试的开发过程可以一次完成,而不必在每次队列需要一种新数据类型时重复进行。
本练习将把从练习5-2开始开发的队列示例改进为泛型队列,以便最终完成这个队列程序。该程序包括一个定义了队列操作的泛型接口、两个异常类和一种队列实现方式:固定大小的队列。当然,读者也可以试验其他类型的泛型队列,如泛型动态队列或泛型循环队列,只要在本练习的基础上改进即可。
同前面的练习9-1中开发的队列一样,本练习也将队列组织到一组单独的文件中:一个代表接口,一个代表队列异常类,一个代表固定队列的实现方式,一个代表演示队列的程序。这种组织方式仿照了实际环境中的项目组织方式。
package javaone.a.beginners.guide.chapterthirteen;// A generic queue interface.
interface IGenQ<T>{// Put an item into the queue.void put(T ch) throws QueueFullException;// Get an item from the queue.T get() throws QueueEmptyException;;
}// An exception for queue-full errors.
class QueueFullException extends Exception{int size;QueueFullException(int s){size = s;}public String toString(){return "\nQueue is full. Maximum size is " + size;}
}// An exception for queue-empty errors.
class QueueEmptyException extends Exception{public String toString(){return "\nQueue is empty.";}
}// A generic, fixed-size queue class.
class GenQueue<T> implements IGenQ<T>{private T q[]; // this array holds the queueprivate int putloc, getloc; // the put and get indices// Construct an empty queue with the given array.public GenQueue(T[] aRef){q = aRef;putloc = getloc = 0;}// Put an item into the queue.public void put(T ch) throws QueueFullException{if(putloc == q.length){throw new QueueFullException(q.length);}q[putloc++] = ch;}// Get a character from the queue.public T get() throws QueueEmptyException{if(getloc == putloc){throw new QueueEmptyException();}return q[getloc++];}
}
/*Try This 13-1Demonstrate a generic queue class.*/
public class ChapterThirteenProgramOne {public static void main(String[] args) {// Create an integer queue.Integer iStore[] = new Integer[10];GenQueue<Integer> q = new GenQueue<Integer>(iStore);Integer iVal;System.out.println("Demonstrate a queue of Integers.");try{for (int i = 0; i < 5; i++) {System.out.println("Adding " + i + " to q.");q.put(i); // add integer value to q}}catch (QueueFullException exc){System.out.println(exc);}System.out.println();try{for (int i = 0; i < 5; i++) {System.out.print("Getting next Integer from q: ");iVal = q.get();System.out.println(iVal);}}catch (QueueEmptyException exc){System.out.println(exc);}System.out.println();// Create a Double queue.Double dStore[] = new Double[10];GenQueue<Double> qTwo = new GenQueue<Double>(dStore);Double dVal;System.out.println("Demonstrate a queue of Doubles.");try{for (int i = 0; i < 5; i++) {System.out.println("Adding " + (double)i/2 + " to qTwo.");qTwo.put((double)i/2);}}catch (QueueFullException exc){System.out.println(exc);}System.out.println();try{for (int i = 0; i < 5; i++) {System.out.print("Getting next Double from qTwo: ");dVal = qTwo.get();System.out.println(dVal);}}catch (QueueEmptyException exc){System.out.println(exc);}}}
13.15 自测题
1. 泛型是Java添加的一项重要功能,因为它使得代码的创建:
A. 类型安全
B. 可重用
C. 可靠
D. 以上都对
答案:D
2. 基本类型能用作类型实参吗?
答案: 不能,类型实参必须是对象类型。
3. 说明如何声明一个名为FlightSched的类,它带有两个泛型形参。
答案:class FlightSched<T, V> {
4. 对于自测题3,修改FlightSched的第二个类型形参,使得它必须扩展Thread。
答案:class FlightSched<T, V extends Thread>
5. 现在,修改FlightSched的第二个类型形参,使它成为第一个类型形参的子类。
答案:class FlightSched<T, V extends T>
6. 就泛型而言,"?"代表什么?它的作用是什么?
答案:“?"是通配符实参,能匹配任何有效的类型。
7. 可以约束通配符实参吗?
答案:可以,通配符实参既可以有上层约束,也可以有下层约束。
8. 泛型方法MyGen()带有一个类型形参。而且,MyGen()带有一个其类型与该类型形参相同的形参。它还返回该类型形参的对象。写出如何声明MyGen()。
答案: <T> T MyGen(T o) {
9. 对于下面的泛型接口:
interface IGenIF<T, V extends T> { // ...
提供实现IGenIF的MyClass类的声明。
答案: class MyClass<T, V extends T> implements IGenIF<T, V> { // ...
10. 对于泛型类Counter<T>,说明如何创建一个其原类型的对象。
答案:要获得Counter<T>的原类型,在不带任何类型规范的情况下只需要使用其名称即可,如下所示:
Counter x = new Counter();
11. 类型形参在运行时存在吗?
答案:不存在,所有的类型形参在编译时都被擦除,由合适的强制转换替代。这一过程称为擦除。
12. 把第9章自测题10中的解决方案 转换为泛型解决方案。在转换过程中,创建一个以泛型方式定义操作push()和pop()的堆栈接口IGenStack。
package javaone.a.beginners.guide.chapterthirteen;// A generic stack.
interface IGenStack<T> {void push(T t) throws StackFullException;T pop() throws StackEmptyException;
}// An exception for stack-full errors.
class StackFullException extends Exception {int size;StackFullException(int s) {size = s;}public String toString() {return "\nStack is full. Maximum size is " +size;}
}// An exception for stack-empty errors.
class StackEmptyException extends Exception {public String toString() {return "\nStack is empty.";}
}// A stack class for characters.
class GenStack<T> implements IGenStack<T> {private T stck[]; // this array holds the stackprivate int tos; // top of stack// Construct an empty stack given its size.GenStack(T[] stckArray){stck = stckArray;tos = 0;}// Construct a stack from a stackGenStack(T[] stackArray, GenStack<T> ob){tos = ob.tos;stck = stackArray;try {if(stck.length < ob.stck.length){throw new StackFullException(stck.length);}}catch (StackFullException exc){System.out.println(exc);}// copy elements.for (int i = 0; i < tos; i++) {stck[i] = ob.stck[i];}}// Construct a stack with initial values.GenStack(T[] stackArray, T[] a){stck = stackArray;for (int i = 0; i < a.length; i++) {try {push(a[i]);}catch (StackFullException exc){System.out.println(exc);}}}// Pusg objects onto the stack.public void push(T obj) throws StackFullException {if(tos == stck.length){throw new StackFullException(stck.length);}stck[tos] = obj;tos++;}// Pop an object from the stack.public T pop() throws StackEmptyException {if(tos == 0){throw new StackEmptyException();}tos--;return stck[tos];}
}
// Demonstrate the GenStack class.
public class ChapterThirteenExerciseTwelve {public static void main(String[] args) {// Construct 10-element empty Integer stack.Integer iStore[] = new Integer[10];GenStack<Integer> stkOne = new GenStack<Integer>(iStore);// Construct stack from array.String name[] = {"One","Two","Three"};String strStore[] = new String[3];GenStack<String> stkTwo = new GenStack<String>(strStore,name);String str;int n;try{// Put some values into stkOnefor (int i = 0; i < 10; i++) {stkOne.push(i);}}catch (StackFullException exc){System.out.println(exc);}// Construct stack from another stack.String strStoreTwo[] = new String[3];GenStack<String> stkThree = new GenStack<String>(strStoreTwo,stkTwo);try{// Show the stacks.System.out.print("Contents of stkOne: ");for (int i = 0; i < 10; i++) {n = stkOne.pop();System.out.print(n + " ");}System.out.println("\n");System.out.print("Contents of stkTwo: ");for (int i = 0; i < 3; i++) {str = stkTwo.pop();System.out.print(str + " ");}System.out.println("\n");System.out.print("Contents of stkThree: ");for (int i = 0; i < 3; i++) {str = stkThree.pop();System.out.print(str + " ");}}catch (StackEmptyException exc){System.out.println(exc);}System.out.println();}}
13. <>是什么?
答案:是菱形运算符用于类型推断。
14. 如何简化下面的语句?
MyClass<Double, String> obj = new MyClass<Double, String>(1.1, "Hi");
答案:
MyClass<Double, String> obj = new MyClass<>(1.1, "Hi");