Java All-in-One Desk Reference For Dummies phần 6 pot

89 295 0
Java All-in-One Desk Reference For Dummies phần 6 pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Chapter 5: Creating Generic Collection Classes In This Chapter ߜ Discovering why the generics feature was invented ߜ Using generics in your own classes ߜ Working with wildcards in a generic class ߜ Examining a pair of classes that demonstrate generics I n the previous two chapters, you’ve seen how you can specify the type for an ArrayList or a LinkedList so the compiler can prevent you from accidentally adding the wrong type of data to the collection. The ArrayList and LinkedList classes are able to do this because they take advantage of a new feature of Java 1.5 called generics. In this chapter, I show you how the generics feature works and how to put it to use in your own classes. Specifically, you see examples of two classes that use the LinkedList class to implement a specific kind of collection. The first is a stack, a collection in which items are always added to the front of the list and retrieved from the front of the list. The second is a queue, a col- lection in which items are added to the end of the list and retrieved from the front. This is one of those chapters where the entire chapter gets a Technical Stuff icon. Frankly, generics is on the leading edge of object-oriented programming. You can get by without knowing any of the information in this chapter, so feel free to skip it if you’re on your way to something more interesting. However, this chapter is worth looking at even if you just want to get an idea of how the ArrayList and LinkedList classes use the new generics feature. And, you might find that someday you want to create your own generic classes. Your friends will surely think you’re a genius. To be sure, I won’t be covering all the intricacies of programming with gener- ics. If your next job happens to be writing Java class libraries for Sun, you’ll need to know a lot more about generics than this chapter covers. I focus just on the basics of writing simple generic classes. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 419 Why Generics? 420 Why Generics? Before Java 1.5, collection classes could hold any type of object. For example, the add method for the ArrayList class had this declaration: public boolean add(Object o) { // code to implement the add method } Thus, you can pass any type of object to the add method, and the array list gladly accepts it. When you retrieved an item from a collection, you had to cast it to the correct object type before you could do anything with it. For example, if you had an array list named empList with Employee objects, you’d use a statement like this one to get the first Employee from the list: Employee e = (Employee)empList.get(0); The trouble is, what if the first item in the list isn’t an Employee? Because the add method accepts any type of object, there was no way to guarantee that only certain types of objects could be added to the collection. That’s why generics were invented. Now, you can declare the ArrayList like this: ArrayList<Employee> empList = new ArrayList<Employee>(); Here, empList is declared as an ArrayList that can hold only Employee types. Now, the add method has a declaration that is the equivalent of this: public boolean add(Employee o) { // code to implement the add method } Thus, you can only add Employee objects to the list. And the get method has a declaration that’s equivalent to this: public Employee get(int index) { // code to implement the get method } Thus, the get method returns Employee objects. You don’t have to cast the result to an Employee because the compiler already knows the object is an Employee. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 420 Book IV Chapter 5 Creating Generic Collection Classes Creating a Generic Class 421 Creating a Generic Class Generics let you create classes that can be used for any type specified by the programmer at compile time. To accomplish that, the Java designers intro- duced a new feature to the language, called formal type parameters. To create a class that uses a formal type parameter, you list the type parameter after the class name in angle brackets. The type parameter has a name — Sun rec- ommends you use single uppercase letters for type parameter names — that you can then use throughout the class anywhere you otherwise use a type. For example, here’s a simplified version of the class declaration for the ArrayList class: public class ArrayList<E> I left out the extends and implements clauses to focus on the formal type parameter: <E>. The E parameter specifies the type of the elements that are stored in the list. Sun recommends the type parameter name E (for Element) for any parameter that specifies element types in a collection. So, consider this statement: ArrayList<Employee> empList; Here, the E parameter is Employee, which simply means that the element type for this instance of the ArrayList class is Employee. Now, take a look at the declaration for the add method for the ArrayList class: public boolean add(E o) { // body of method omitted (thank you) } Where you normally expect to see a parameter type, you see the letter E. Thus, this method declaration specifies that the type for the o parameter is the type specified for the formal type parameter E. If E is Employee, that means the add method only accepts Employee objects. So far, so good. Now take a look at how you can use a formal type parameter as a return type. Here’s the declaration for the get method: public E get(int index) { // body of method omitted (you’re welcome) } Here, E is specified as the return type. That means that if E is Employee, this method returns Employee objects. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 421 A Generic Stack Class 422 One final technique you need to know before moving on: You can use the formal type parameter within your class to create objects of any other class that accepts formal type parameters. For example, the clone method of the ArrayList class is written like this: public Object clone() { try { ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = (E[])new Object[size]; System.arraycopy(elementData, 0, v.elementData, 0, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn’t happen since we’re Cloneable throw new InternalError(); } } You don’t need to look much at the details in this method; just notice that the first statement in the try block declares an ArrayList of type <E>. In other words, the ArrayList class uses its own formal type parameter to create another array list object of the same type. If you think about it, that makes perfect sense. After all, that’s what the clone method does: creates another array list just like this one. The key benefit of generics is that this typing happens at compile time. Thus, after you specify the value of a formal type parameter, the compiler knows how to do the type checking implied by the parameter. That’s how it knows not to let you add String objects to an Employee collection. A Generic Stack Class Now that you’ve seen the basics of creating generic classes, in this section you look at a simple generic class that implements a stack. A stack is a simple type of collection that lets you add objects to the top of the collec- tion and remove them from the top. I name this Stack class in this section GenStack and it has five methods: ✦ push: This method adds an object to the top of the stack. ✦ pop: This method retrieves the top item from the stack. The item is removed from the stack in the process. If the stack is empty, this method returns null. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 422 Book IV Chapter 5 Creating Generic Collection Classes A Generic Stack Class 423 ✦ peek: This method lets you peek at the top item on the stack. In other words, it returns the top item without removing it. If the stack is empty, it returns null. ✦ hasItems: This method returns a boolean value of true if the stack has at least one item in it. ✦ size: This method returns an int value that indicates how many items are in the stack. The GenStack class uses a LinkedList to implement the stack. For the most part, this class simply exposes the various methods of the LinkedList class using names that are more appropriate for a stack. The complete code for the GenStack class is shown in Listing 5-1. LISTING 5-1:THE GENSTACK CLASS import java.util.*; public class GenStack<E> ➞ 3 { private LinkedList<E> list = new LinkedList<E>(); ➞ 5 public void push(E item) ➞ 7 { list.addFirst(item); } public E pop() ➞ 12 { return list.poll(); } public E peek() ➞ 17 { return list.peek(); } public boolean hasItems() ➞ 22 { return !list.isEmpty(); } public int size() ➞ 27 { return list.size(); } } 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 423 A Generic Stack Class 424 The following paragraphs highlight the important details in this class: ➞ 3 The class declaration specifies the formal type parameter <E>. Thus, users of this class can specify the type for the stack’s elements. ➞ 5 This class uses a private LinkedList object list to keep the items stored in the stack. The LinkedList is declared with the same type as the GenStack class itself. Thus, if the E type parameter is Employee, the type for this LinkedList is Employee. ➞ 7 The push method accepts a parameter of type E. It uses the linked list’s addFirst method to add the item to the beginning of the list. ➞ 12 The pop method returns a value of type E. It uses the linked list’s poll method, which removes and returns the first element in the linked list. If the list is empty, the poll method — and therefore the pop method — returns null. ➞ 17 The peek method also returns a value of type E. It simply returns the result of the linked list’s peek method. ➞ 22 The hasItems method returns the opposite of the linked list’s isEmpty method. ➞ 27 The size method simply returns the result of the linked list’s size method. So that’s all there is to it. The following program gives the GenStack class a little workout to make sure it functions properly: public class GenStackTest { public static void main(String[] args) { GenStack<String> gs = new GenStack<String>(); System.out.println( “Pushing four items onto the stack.”); gs.push(“One”); gs.push(“Two”); gs.push(“Three”); gs.push(“Four”); System.out.println(“There are “ + gs.size() + “ items in the stack.\n”); System.out.println(“The top item is: “ + gs.peek() + “\n”); 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 424 Book IV Chapter 5 Creating Generic Collection Classes A Generic Stack Class 425 System.out.println(“There are still “ + gs.size() + “ items in the stack.\n”); System.out.println(“Popping everything:”); while (gs.hasItems()) System.out.println(gs.pop()); System.out.println(“There are now “ + gs.size() + “ items in the stack.\n”); System.out.println(“The top item is: “ + gs.peek() + “\n”); } } This program creates a GenStack object that can hold String objects. It then pushes four strings onto the stack and prints the number of items in the stack. Next, it uses the peek method to print the top item and again prints the number of items in the stack, just to make sure the peek method doesn’t accidentally remove the item. Next, it uses a while loop to pop each item off the stack and print it. Then it once again prints the number of items (which should now be zero), and it peeks at the top item (which should be null). Here’s the output that results when you run this program: Pushing four items onto the stack. There are 4 items in the stack. The top item is: Four There are still 4 items in the stack. Popping everything: Four Three Two One There are now 0 items in the stack. The top item is: null Notice that when the program pops the items off the stack, they come out in reverse order in which they were pushed on to the stack. That’s normal behavior for stacks. In fact, stacks are sometimes called Last-In, First-Out lists, or LIFO lists, for this very reason. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 425 Using Wildcard Type Parameters 426 Using Wildcard Type Parameters Suppose you have a method that’s declared like this: public void addItems(ArrayList<Object> list) { // body of method not shown } Thought question: Does the following statement compile? addItems(new ArrayList<String>()); Answer: Nope. That’s surprising because String is a subtype of Object. So you’d think that a parameter that says it accepts an ArrayList of objects accepts an ArrayList of strings. Unfortunately, inheritance doesn’t work quite that way when it comes to formal type parameters. Instead, you have to use another feature of gener- ics, called wildcards. In short, if you want to create a method that accepts any type of ArrayList, you have to code the method like this: public void addItems(ArrayList<?> list) Here, the question mark indicates that you can code any kind of type here. That’s almost as good as inheritance, but what if you want to actually limit the parameter to collections of a specific superclass? For example, suppose you’re working on a payroll system that has an Employee superclass with two subclasses named HourlyEmployee and SalariedEmployee, and you want this method to accept an ArrayList of Employee objects, HourlyEmployee objects, or SalariedEmployee objects? In that case, you can add an extends clause to the wildcard, like this: public void addItems(ArrayList<? extends Employee> list) Then, you can call the addItems method with an ArrayList of type Employee, HourlyEmployee, or SalariedEmployee. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 426 Book IV Chapter 5 Creating Generic Collection Classes A Generic Queue Class 427 Now, before you call it a day, take this example one step further. Suppose this addItems method appears in a generic class that uses a formal type parameter <E> to specify the type of elements the class accepts, and you want the addItems method to accept an ArrayList of type E or any of its subclasses. To do that, you’d declare the addItems method like this: public void addItems(ArrayList<? extends E> list) Here, the wildcard type parameter <? extends E> simply means that the ArrayList can be of type E or any type that extends E. A Generic Queue Class Now that you’ve seen how to use wildcards in a generic class, this section presents a generic class that implements a queue. A queue is another type of collection that lets you add objects to the end of the collection and remove them from the top. Queues are commonly used in all sort of appli- cations, from data processing applications to sophisticated networking systems. This queue class is named GenQueue and has the following methods: ✦ enqueue: This method adds an object to the end of the queue. ✦ dequeue: This method retrieves the first item from the queue. The item is removed from the queue in the process. If the queue is empty, this method returns null. ✦ hasItems: This method returns a boolean value of true if the queue has at least one item in it. ✦ size: This method returns an int value that indicates how many items are in the stack. ✦ addItems: This method accepts another GenQueue object as a parame- ter. All the items in that queue are added to this queue. In the process, all the items from the queue passed to the method are removed. The GenQueue parameter must be of the same type as this queue or a sub- type of this queue’s type. The GenQueue class uses a LinkedList to implement its queue. The com- plete code for the GenQueue class is shown in Listing 5-2. 32_58961X bk04ch05.qxd 3/29/05 3:49 PM Page 427 [...]... engines are not started all at the same time Instead, engine 1 is started at T-minus 6. 6 seconds, engine 2 is started 120 milliseconds Creating a Thread 435 later at T-minus 6. 48 seconds, and engine 3 120 milliseconds after that at T-minus 6. 36 seconds I fudge in my program and start all three engines at T-minus 6 seconds For this program, I don’t actually start any rocket engines or release huge amounts... programs in Java in Book VI ✦ Indeed, the Java Virtual Machine itself uses threading for some of its housekeeping chores For example, the garbage collector runs as a separate thread so it can constantly monitor the state of the VM’s memory and decide when it needs to remove objects that are no longer being used to create some free memory Creating a Thread Suppose you’re developing software for NASA,... variations in their timings can cause the thread behaviors to change For example, if you run the program several times in a row, you’ll discover that sometimes the Start engines! message appears after the T minus 6 message, and sometimes it appears before the T minus 6 message That might not be a big deal to you, but it would probably be disastrous for the astronauts on the shuttle What these classes really... simply returns the value of the t variable 60 The start of the LaunchEvent class 64 A private field of type TimeMonitor is used to access the countdown clock A reference to this object is passed to the LaunchEvent class via its constructor The constructor simply stores that reference in this field ➞81 The while loop includes a call to Thread.sleep that sleeps for just 10 milliseconds Thus, this loop... from 20,000 Thus, if the desired start time is 6 seconds, the sleep method sleeps for 14,000 milliseconds — that is, 14 seconds ➞20 When the thread wakes up, it displays the message passed via its constructor on the console Using the CountDownApp class Now that you’ve seen the code for the LaunchEvent and CountDown Clock classes, Listing 1-3 shows the code for a CountDownApp class that uses these classes... method for this class by using an ArrayList to store the Runnable objects Then, you can start all the LaunchEvent threads by using an enhanced for loop Here’s what the improved code looks like: public static void main(String[] args) { Thread clock = new CountDownClock(); ArrayList events = new ArrayList(); events.add(new LaunchEvent( 16, “Flood the pad!”)); events.add(new LaunchEvent (6, ... book are available at www .dummies. com/go/javaaiofd Understanding Threads A thread is a single sequence of executable code within a larger program All the programs shown so far in this book have used just one thread — the 434 Creating a Thread main thread that starts automatically when you run the program However, Java lets you create programs that start additional threads to perform specific tasks You’re... launch events for the NASA application, I create a Runnable object named LaunchEvent The constructor for this class accepts two parameters: the countdown time at which the event fires, and the message that is displayed when the time arrives Then, the run method for this class uses Thread.sleep to wait until the desired time arrives Then, it displays the message Listing 1-2 shows the code for this class... events = new ArrayList(); events.add( new LaunchEvent( 16, “Flood the pad!”, clock)); events.add( new LaunchEvent (6, “Start engines!”, clock)); events.add( new LaunchEvent(0, “Liftoff!”, clock)); clock.start(); for (Runnable e : events) new Thread(e).start(); } } interface TimeMonitor { int getTime(); void abortCountDown(); } ➞ 26 class CountDownClock extends Thread implements TimeMonitor {... Thread.sleep(20000 - (start * 1000)); } catch (InterruptedException e) {} System.out.println(message); } } Book V Chapter 1 ➞ 1 ➞ 6 ➞ 16 ➞ 20 440 Implementing the Runnable Interface The following paragraphs draw your attention to the listing’s key lines: ➞ 1 This class implements the Runnable interface ➞ 6 The constructor accepts two parameters: an integer representing the start time (in seconds) and a string message . 3:49 PM Page 419 Why Generics? 420 Why Generics? Before Java 1.5, collection classes could hold any type of object. For example, the add method for the ArrayList class had this declaration: public. find out about creating GUI programs in Java in Book VI. ✦ Indeed, the Java Virtual Machine itself uses threading for some of its housekeeping chores. For example, the garbage collector runs. T-minus 6. 6 seconds, engine 2 is started 120 milliseconds 34_58 961 X bk05ch01.qxd 3/29/05 3:47 PM Page 434 Book V Chapter 1 Programming Threads Creating a Thread 435 later at T-minus 6. 48 seconds,

Ngày đăng: 12/08/2014, 19:21

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan