University of North Carolina at Asheville

CSCI 202: Introduction to Data Structures


Lab 13: Generic Classes and Methods

[Introduction] [Instructions] [What To Submit]


Introduction

In this lab you will learn to how use generic classes to write applications that deal with the issues of data type checking in a new way. In your next lab you will build on this knowledge, and learn how to work with a useful set of generic Java library classes known collectively as the Java Collections Framework.


Instructions:

  1. Login and enter the directory csci/202/labs. Launch the NetBeans IDE, select the File/New Project... option in the toplevel menu bar, and create a new project called Lab13. Define the project to be a General Java Application and accept all the default settings so that NetBeans will automatically write a class lab13.Main for you. You should find the source file for this class in Lab13/src/lab13.
  2. Download the following files and import them into your Lab13/src/lab13 project folder:

    Stack.java StackTest0.java StackTest1.java StackTest2.java
  3. Open the file StackTest0.java in the NetBeans editor and scan its contents. You should soon see that any of the Stack classes you developed in your earlier labs, as for example Lab 07, could be used in conjunction with the StackTest0 application.

    Now attempt to compile the single file StackTest0.java, without building the whole Lab13 project just yet. To do this, select the Projects view and right-click on the filename StackTest0.java. Then select the Compile File option in the popup menu.

    The NetBeans output window should immediately display some red-line messages, as shown in the image below:

    In slightly edited form (omitting full pathnames), the messages of concern read as follows:

    
    	Note: StackTest0.java uses unchecked or unsafe operations.
    	Note: Recompile with -Xlint:unchecked for details.
    
    The compiler is trying to warn you here that your application is not making totally correct use of the class Stack. That is because the version of Stack.java used in this lab is defined as a generic class, and our StackTest0 application is ignoring that fact.

    To see more details about this, right-click on the project name Lab13 and raise its Properties dialog (just the way you start out to add JAR files to your project classpath). But this time, instead of clicking the category Libraries in the left-hand subpanel, select the Build/Compiling option. This will raise a subdialog that appears as shown below:

    Look for the blank textbox labeled Additional Compiler Options. Enter the option -Xlint:unchecked into this box, and then click OK. If you now attempt to compile StackTest0.java again, the output window should look even worse than before:

    But if you look more closely, you should quickly see that these messages are all just warnings, not outright compiler errors. The main difference between the two is that warnings do not prevent the compiler from generating at least some sort of bytecode (.class files). In fact, if you try now to Run the file StackTest0 it should work just as you might expect it to:

  4. Your next step is to revise StackTest0.java so that it can be compiled without generating all those compiler warnings. The key step here is to find the line
    
    	Stack stack = new Stack();
    
    and change it to read as follows:
    
    	Stack<Object> stack = new Stack<Object>();
    
    As you can probably guess, this change tells the compiler explicitly that stack will accept Object values (which in effect includes all other types of objects, such as String, Color, or whatever). With the original version the compiler actually ended up making this same assumption, but only after issuing a warning about the use of raw types (generic classes with no type parameters in angle brackets).

    Try making this one change and recompiling StackTest0. You should see the warnings go away. And of course when you run StackTest0 it should work just as it did before.

    When you reach this point, show your new version of StackTest0 to your lab instructor.

  5. Now open StackTest1 in the NetBeans editor and scan its contents. You should quickly see that this application also creates a Stack as a so-called raw type, and then pushes a sequence of Integer values onto it. In a following while loop, it first prints out the top value and then pops it from the stack, adding each popped value to a running sum.

    Use the Compile File menu option to compile StackTest1. As you should expect, the compiler will again issue warnings about the use of raw types. As a first attempt to remove these warnings, try changing the Stack declaration to

    
    	Stack<Object> stack = new Stack<Object>();
    
    and recompile. You should no longer see the warnings.

    That is progress, but you can do better: go back and change the declaration to read

    
    	Stack<Integer> stack = new Stack<Integer>();
    
    and try again. You should still see no warnings. But now go in again and change the line that reads
    
    	sum += (Integer) stack.pop();
    
    to
    
    	sum += stack.pop();
    
    In other words, remove the cast operator. The cast to the Integer type is in fact unnecessary if the compiler knows that the Stack can store only Integer values. In a larger program, the ability to remove lots of cast operators can be a major improvement. But the restriction to the Integer type has another advantage: now the compiler can detect possible errors that otherwise would have been found only later at runtime, usually in the form of a ClassCastException.

    As a simple illustration of this last point, open StackTest2.java in the NetBeans editor. This is a tiny application that creates two Stack instances, one for String values and one for Integer values. Compile and run this program as is, just to be sure that you get no warnings about raw types and that its output is what you would expect. Then try adding lines like

    
    	strs.push(789);
    
    or
    
    	ints.push("789");
    
    to the sequences of push() statements. In either case the compiler should immediately report an error, and in fact pinpoint the line number where the error actually occurred. With runtime ClassCastException errors, the reported line may be far from the point where the real error was made. It is for both of these reasons that generic classes were introduced into the Java language as of version 1.5.
  6. To start your final task in this lab, open Stack.java in the NetBeans editor and look it over. Try to spot the places that make this a generic class definition, as opposed to the ordinary class definitions that you have seen earlier. In particular, note the use of the identifier E in angle brackets in the class header:
    
    	public class Stack<E>
    
    The symbol E is just a placeholder, which serves very much the same purpose as a parameter name in a method definition. Later in the code you will see occurrences of E where you might have expected, say, Object to appear. What happens is that when an application makes a declaration like
    
    	Stack<Integer> stack = new Stack<Integer>();
    
    the generic definition is used to make a new Stack object, in which all references to E are replaced by Integer.

    Of course that is just the first approximation to the truth, and there are lots of details that are glossed over here. But just knowing this much should enable you to convert a simple, ordinary class definition into its generic equivalent. Now your textbook actually defines several generic demo classes in Chapter 21, including its own version of a GenericStack (Listing 21.1, p. 688). So by following any of these examples you could easily implement a generic version of a Queue as your final exercise in this lab. But to make things at least slightly more interesting, you get to deal with the List class that you encountered earlier in your labs. To start out, download the following two additional files and import them into your Lab13/src/lab13 project folder:

    List.java ListTest.java
  7. Your task is simply to convert the class definition for List into a generic version. Of course you should use Stack.java as a guide, and you may also get help from looking at the textbook demos.

    When you get the List conversion done, you should be able to compile and run the test application with no compiler or runtime errors. So good luck...

    As usual, be sure to show your final results to your lab instructor before you logout.


What To Submit

When your project is complete and working correctly, demonstrate it to your lab instructor. Then, before you exit NetBeans, clean your Lab13 project. Finally, before you logout, open a terminal window and use the cd command to enter your csci/202/labs directory. Then create a JAR file of your Lab13 project folder, using the command

jar cf Lab13Project.jar Lab13
Please leave both your Lab13 project folder and Lab13Project.jar in your csci/202/labs directory for the remainder of the semester.