Sunteți pe pagina 1din 21

All rights reserved.

Reproduction and/or distribution in whole or in


part in electronic, paper or other forms without written permission
is prohibited.

Java ReferencePoint Suite


SkillSoft Corporation. (c) 2002. Copying Prohibited.

Reprinted for Balaji Nallathambi, Verizon


Balaji@verizon.com
Reprinted with permission as a subscription benefit of Books24x7,
http://www.books24x7.com/

Table of Contents
Point 9: Working with Java Generics..............................................................................................1
Introducing Generics........................................................................................................................2
Overview of Generic Classes..................................................................................................2
Implementing Generic Classes...............................................................................................3
Using Generics with Interfaces.......................................................................................................8
Implementing Generic Interfaces............................................................................................8
Subtyping and Generics........................................................................................................11
Using Wildcards..............................................................................................................................13
Working with Wildcards.........................................................................................................13
Using Generic Methods........................................................................................................17
Related Topics................................................................................................................................19

Point 9: Working with Java Generics


S. Kartikeyan
The generics programming model is an extension to the Java programming language introduced
with the Java Development Kit (JDK) 1.5. Generics allow you to specify the object type to be
associated with a container class when instantiating the class. As a result, you can avoid
typecasting code when working with generic collection classes. Using generics reduces the amount
of code and makes programs more readable and less prone to errors.
This ReferencePoint introduces generics and explains the use of generics to increase the
readability of Java programs. It also explains how to create and use Java programs that implement
generics.

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Introducing Generics
Generics allow you to design Application Programming Interfaces (APIs) that provide general
functionality applicable to multiple types. The type of an object is the information about the class
and hierarchy of classes and interfaces to which the object belongs. Using generics you can specify
the type information of data using a parameter, which means that the type can be a variable or it
can change at runtime.
Generics is a popular model of programming supported by functional languages, such as Haskell.
Various objectoriented languages, such as C++ and Eiffel, also support generics. The C++
language implements generics through templates.
Note A functional language is a language that supports and encourages programming in a
functional style. Functional programming is a style of programming that evaluates
expressions, rather than executing commands with variables. For example, to calculate the
sum of integers from 1 to 10, a functional programming language uses an expression, such
as sum [1..10], rather than executing commands such as:
total = 0;
for (i=1; i<=10; ++i)
total += i;

Overview of Generic Classes


When you work with data structures such as an array, list, or stack, you need to track the types of
the elements stored in data structures. While creating arrays in Java, you can specify the type you
require but while creating a Collection object such as an ArrayList or Vector object, it is not possible
to specify the types. For example, the following code shows how to create an ArrayList object and
insert a String object to the data structure:
ArrayList strList = new ArrayList();
strList.add(new String("Denver"));

When you want to retrieve the object stored within the strList object, you need to track the type of
the objects stored in it. You can retrieve the objects stored in the strList object using the following
statement:
String str = (String) strList.iterator().next();

You should typecast the objects returned, into the desired type because Collection objects in Java
return elements of type, Object. Typecasting is an error prone operation because programmers tend
to miss out typecasting code and may issue wrong casts at runtime. This may give rise to bugs at
later stages of development. In addition, typecasting is an unsafe operation because casts may fail
at runtime.
You need not typecast elements when using generics because generics allow you to specify the
type of elements stored in a data structure using a parameter, at the time of program development.
When you use generics in your programs, the compiler inserts typecasts at appropriate places to
implement typecasting.
Using generics, you can state in the code that you require an ArrayList object that stores only String
objects. You specify the type that you require within angled brackets, <>. You can use this notation
when you use a generically defined class from an API in your programs or when you want to create
generic classes yourself. The following code snippet shows how you can instantiate a generic List
object:
ArrayList<String> strList = new ArrayList<String>();
strList.add("Denver");

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

The first line in the above snippet creates an ArrayList object that stores only strings. When you
retrieve the String object from the ArrayList object, you do not have to typecast it. The following
snippet shows how to retrieve a String object from the ArrayList object, without writing the code for
typecasting:
String str = strList.iterator().next();

You specify the parameter type when instantiating an object of the class. For example, if you create
a class, Graph, which can hold multiple types of data within it, then the declaration for this class
would be:
public class Graph<A> extends SomeClass implements SomeInterface{
}

The above snippet specifies the parameter type of the class within angled brackets as A. You use
this convention when you create custom generic classes. Using a single capital letter is not
mandatory, but doing helps avoid confusion with other data types and class names. JDK 1.5
replaces the entire collection framework in the java.util package with a generic collection framework.
As a result, you can use the generic versions of collection classes in Java programs.
The addition of generic extension to the Java language does not call for a change in Java Virtual
Machine (JVM). This is because the Java compiler applies generics only at compile time. It uses the
parametric information in the source code to provide type safety.
Note

Type safety means an object retains its original type, and errors due to type mismatch
are trapped during compile and runtime. A language and tools associated with the
language should ensure type safety if the language is type safe.

The compiler compiles the source using a technique called erasure. Erasure ensures that the
compiler does not retain any generics code of the source code in the compiled code. The compiler
inserts appropriate casting corresponding to the instances of generics code into the bytecode to
reflect the parametric information. As a result, the compiled bytecode of classes written using
generics do not contain any information relating to generics. This means code written using JDK 1.5
is backward compatible with JRE 1.4.
JDK versions prior to 1.5 implement a subtyping rule by which all objects are of type Object. This
allows you to store objects of multiple types in one data structure or collection class. When creating
arrays you always mention the type of the object to be stored in the array. Generics allow you treat
other data structures and collection classes similar to arrays, whereby you can explicitly state that a
data structure can hold objects of only one type.

Implementing Generic Classes


Generics are useful when you develop custom data structures. For example, you can create a
circular linked list using the generic model, which ensures type safety to all other classes that may
use the circular linked list.

Note The collection framework does not implement circular linked lists.
Circular linked lists are linked lists whose last node refers back to the first node of the list. This type
of list is useful when you want to keep traversing the list and accessing the elements in the list
repeatedly in a circular fashion. For example, you can use a circular linked list when you want to
create an animation using few still images as frames.

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

Note

To learn more about linked lists and other data structures, see the Implementing
Linked Lists in C++ ReferencePoint.

To create a circular linked list using generics, create two classes, Node and CircularList. Listing
191 shows the complete code for the CircularList.java file.
Listing 191: The CircularList.java File

class Node<A>
{
//Declaring the element of type A
A element;
/*
Reference or pointer to the next node in the chain, the reference is parameterized
*/
Node<A> nextNode;
// No argument Constructor
public Node()
{
element = null;
nextNode = null;
}
/*
Constructor that takes two arguments, the element and reference to the next node
*/
public Node(A elem, Node<A> n)
{
element = elem;
nextNode = n;
}
//Setter method for the element member variable
public void setElement(A elem)
{
element = elem;
}
//Getter method for the element member variable
public A getElement()
{
return element;
}
//Setter method for the Node member variable
public void setNextNode(Node<A> n)
{
nextNode = n;
}
//Getter method for the Node member variable
public Node<A> getNextNode()
{
return nextNode;
}
}
//The generic CircularList class
public class CircularList<A>
{
//reference to the head node
protected Node<A> header;
//reference to the tail node
protected Node<A> trailer;
//reference to the current node
protected Node<A> cursor;
//reference to the traveling node
protected Node<A> traverser;
protected int size;
public CircularList()
{
header = new Node<A>();
trailer = new Node<A>();
trailer.setNextNode(header);
cursor = null;
size = 0;
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

}
public int getSize()
{
return size;
}
public boolean isEmpty()
{
return (size == 0);
}
//adds an element to the end of the list
public void append(A elem)
{
Node<A> temp = new Node<A>();
temp.setElement(elem);
temp.setNextNode(trailer);
if(isEmpty())
{
header.setNextNode(temp);
}else
{
cursor.setNextNode(temp);
}
cursor = temp;
size++;
}
//returns the first node in the list. It does not return header
public Node<A> getFirstNode()
{
return header;
}
/*
Sets the traveling node to the header. Used when traversing list
*/
public void setTraverserToTop()
{
traverser = header;
}
//Returns the last node of the list.
public Node<A> getLastNode()
{
return trailer;
}
/*
Returns the next node in the list from the current position of the traveling node
*/
public Node<A> getNext()
{
traverser = traverser.getNextNode();
if(traverser == header)
{
traverser = traverser.getNextNode();
}else if(traverser == trailer)
{
traverser = traverser.getNextNode().getNextNode();
}
return traverser;
}
}

In the above code, the Node class represents a single node in the list. A Node object contains a
reference to next node in the linked list and a reference to the element that it contains. You can
specify the parameter type of the element, which the node can contain, when creating an instance
of the Node class.
The CircularList class represents a circularly linked list. The CircularList class contains references to
four Node objects, header, trailer, cursor, and traverser. The header object represents the beginning
of the list and the trailer object represents the end of the list. The cursor object represents the
position where the class would add the next element and the traverser object helps in traversing the
list. You can specify the parameter type of the CircularList class when instantiating the class.
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

A program called Animator uses this CircularList class. The Animator program displays an
animation created by displaying few still images successively. Listing 192 shows the complete
code for the Animator.java program:
Listing 192: The Animator.java Program

import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
public class Animator extends JApplet implements Runnable
{
Image img;
CircularList<Image> cl;
Thread thread;
String imageName = "Anim/anim";
String extension = ".jpg";
MediaTracker mt;
public Animator()
{
/*
Creating a CircularList object that stores image objects
*/
cl = new CircularList<Image>();
thread = new Thread(this);
mt = new MediaTracker(this);
}
public void init()
{
try{
URL docBase = getCodeBase();
String url = docBase.toString() + imageName;
for(int i = 1; i<= 8; i++)
{
String temp = url+String.valueOf(i)+extension;
System.out.println(temp);
img = getImage(new URL(temp));
mt.addImage(img, i);
cl.append(img);
}
}catch(MalformedURLException mue)
{
System.out.println(mue);
}
}
public void start()
{
cl.setTraverserToTop();
thread.start();
}
public void paint(Graphics g)
{
if(mt.checkAll())
{
g.drawImage(cl.getNext().getElement(), 0, 0, this);
}
}
public void run()
{
try{
mt.waitForAll();
while(true)
{
repaint();
Thread.sleep(50);
}
}catch(InterruptedException ie)
{
System.out.println(ie);
}
}
}
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

In the above code, the Animator class extends the JApplet class and implements the Runnable
interface. This class reads images from the code base of the applet and stores them in a
CircularList object. The applet uses a MediaTracker object to read these images from the
CircularList object. The applet then traverses the CircularList object in an infinite loop to display the
animation.
The CircularList object includes a parameter of type Image. This means only objects of type Image
can be stored within the CircularList object. The thread object invokes the paint() method once in
every 50 milliseconds. The paint() method retrieves images from the CircularList object and paints
them on the screen. You do not have to add code that typecasts the object retrieved from the list
into an image. You use the objects directly.
Note To run this program, you should install JDK1.5 on your system. You can download the
JDK1.5 Beta from http://java.sun.com/j2se/1.5.0/download.jsp.
Compile all the class files using the javac command from the command line. Use a browser that
supports Java to view the applet. Figure 191 shows the Animator applet displaying the animation:

Figure 191: The Animator Applet Program

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Using Generics with Interfaces


Similar to classes, interfaces can also be generic. The syntax for declaring a generic interface is the
same as that of a class. Interfaces contain only abstract methods. As a result, a class that inherits
from an interface provides implementation to methods declared in the interface. When methods in
an interface receive or return objects of type Object, you need to typecast these objects to
appropriate types to use them. Using generics, you can avoid this typecasting code by specifying
parameter type for the interfaces.
For example, the List interface in the collections framework of JDK1.4 consists of the iterator()
method. A class that implements the List interface should provide an implementation to the iterator()
method. The Iterator object returned by this implementation is of type Object. To use this object you
should provide typecasting code to convert this object into an object of type Iterator.
To avoid typecasting and simplify coding, you can enhance interfaces with parametric information.
Listing 193 shows the List interface in the collection framework:
Listing 193: The TestListClient Class
class TestListClient
{
public static void main(String args[])
{
ArrayList al = new ArrayList();
tl.add("ABC");
tl.add("XYZ");
tl.add("PQR");
//iterate over the nodes
Iterator i = al.iterator();
while(i.hasNext())
{
String temp = (String) i.next();
System.out.println(temp);
}
}
}

The above code uses typecasting inside a while loop. The objects contained in the ArrayList object
are strings, but you need to typecast these objects to use them. You can avoid such typecasting, if
you implement generic interfaces.

Implementing Generic Interfaces


Generic interfaces, similar to generic classes, are useful when used with data structures and
container classes. For example, you can develop a circular linked list that uses generic interfaces.
Listing 194 shows two interfaces, CustomList and Traverser:
Listing 194: The CustomList and Traverser Interfaces
public interface CustomList<A>
{
public void append(A x);
public Traverser<A> getTraverser();
}
public interface Traverser<A>
{
public void setTraverserToTop();
public Node<A> getNext();
}

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

The above code defines two interfaces, CustomList and Traverser. These two interfaces are similar
to List and Iterator interfaces of the collection framework.
You can develop a CircularList class that implements the interfaces, CustomList and Traverser. The
CircularList class uses the Node class that represents the nodes of the CircularList object. Listing
195 shows the code for the CircularList class and the Node Class:
Listing 195: The CircularList and Node Classes

class Node<A>
{
A element;
Node<A> nextNode;
public Node()
{
element = null;
nextNode = null;
}
public Node(A elem, Node<A> n)
{
element = elem;
nextNode = n;
}
public void setElement(A elem)
{
element = elem;
}
public A getElement()
{
return element;
}
public void setNextNode(Node<A> n)
{
nextNode = n;
}
public Node<A> getNextNode()
{
return nextNode;
}
}
public class CircularList<A> implements CustomList<A>, Traverser<A>
{
protected Node<A> header;
protected Node<A> trailer;
protected Node<A> cursor;
protected Node<A> traverser;
protected int size;
public CircularList()
{
header = new Node<A>();
trailer = new Node<A>();
trailer.setNextNode(header);
cursor = null;
size = 0;
}
public int getSize()
{
return size;
}
public boolean isEmpty()
{
return (size == 0);
}
public void append(A elem)
{
Node<A> temp = new Node<A>();
temp.setElement(elem);
temp.setNextNode(trailer);
if(isEmpty())
{
header.setNextNode(temp);
}else
{
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

10

cursor.setNextNode(temp);
}
cursor = temp;
size++;
}
public Node<A> getFirstNode()
{
return header;
}
public void setTraverserToTop()
{
traverser = header;
}
public Node<A> getLastNode()
{
return trailer;
}
public Node<A> getNext()
{
traverser = traverser.getNextNode();
if(traverser == header)
{
traverser = traverser.getNextNode();
}else if(traverser == trailer)
{
traverser = traverser.getNextNode().getNextNode();
}
return traverser;
}
public Traverser<A> getTraverser()
{
return this;
}
}

In the above code, the CircularList class implements the Traverser and CustomList interfaces. The
methods in these interfaces, append(A x), getTraverser(), setTraverserToTop(), and getNext(), are
overridden in the CircularList class.
The ParametrizedInterfaceTest program uses the CircularList class and the generic interfaces, as
shown in Listing 196:
Listing 196: The ParametrizedInterfaceTest Program

public class ParametrizedInterfaceTest


{
public static void main(String[] args)
{
CircularList<Integer> intList = new CircularList<Integer>();
CircularList<String> stringList = new CircularList<String>();
//populate integer list
for(int i = 0; i<25; i++)
{
intList.append(i);
}
//populate String list
stringList.append("Johnny");
stringList.append("Tommy");
stringList.append("Lenny");
stringList.append("Karen");
stringList.append("Helen");
stringList.append("Valerie");
Traverser<Integer> intTraverser = intList.getTraverser();
intTraverser.setTraverserToTop();
System.out.println("Traversing Integer List");
for(int i = 0; i<25; i++)
{
System.out.print(intTraverser.getNext().getElement() + " ");
}
System.out.println();
System.out.println("");
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

11

Traverser<String> strTraverser = stringList.getTraverser();


strTraverser.setTraverserToTop();
System.out.println("Traversing String List");
for(int i = 0; i<5; i++)
{
System.out.print(strTraverser.getNext().getElement()+ " ,");
}
System.out.println();
System.out.println("");
}
}

The ParameterizedInterfaceTest program contains a main() method, which creates two instances of
the CircularList class. One of these objects contains a list of String objects and the other object
contains a list of Integer objects. The methods declared in the interfaces, CustomList and Traverser
populate and traverse these lists. The program does not contain any typecasting code. Figure
192 shows the output of the ParametrizedInterfaceTest program:

Figure 192: The Output of ParametrizedInterfaceTest Program

Subtyping and Generics


In Java, type is the signature associated with variables, objects, and methods. With respect to a
variable, the data type is its type and with respect to a method, its declaration or signature is its
type. When you derive a new type from an existing type, the derived type is called a subtype. In
Java, the type of an object is its class. As a result, when you subclass a class in Java, you subtype
the class. You can pass a subclass object to a method that expects a superclass object as its
parameter. Overridden methods in a subclass should also be of the same type as in the superclass.
This is how Java implements polymorphism. The type of subtyping supported by Java is known as
covariant subtyping. In other words, all objects in Java are of type Object because all classes in
Java inherit from the Object class. Listing 197 shows an example of covariant subtyping in Java:
Listing 197: Covariant Subtyping in Java
Vector v = new Vector ();
String name = "Eric";
String city = "Boston";
Integer age = new Integer (25);
v.add(name);
v.add(city);
v.add(age);

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

12

The above snippet adds two String objects and an Integer object to a Vector object. However, the
Vector object recognizes the string and Integer objects as Object objects. You can add objects with
different data types into a single collection object in JDK 1.4.
In generics, subtyping is not covariant but is invariant. When subtyping is invariant, a subclass
object is not a type of its superclass object. Listing 198 shows an example of subtyping in
generics:
Listing 198: Subtyping in Generics
Vector<String> strVec = new Vector<String>();
String name = "Eric";
String city = "Boston";
Integer age = new Integer (25);
strVec.add(name);
strVec.add(city);
Vector<Object> objVec = strVec;
ObjVec.add(age);

The above snippet does not compile in JDK 1.5 with generics. The line Vector<Object> objVec =
strVec throws a compile time error message. This means in Java with generics a Vector of Strings
is not a Vector of Objects. You can generalize this by stating that if ABCD is a class, XYZ is a
subclass of ABCD, and E is a generic type declaration involving ABCD, then E<XYZ> is not a
subtype of E<ABCD>. The invariance of types is applicable only to generic types and normal class
subtypes are still covariant in JDK 1.5:
Irrespective of the type enclosed by a generic class, you cannot differentiate invocations to this
class that are generic, based on their parameter types. A Vector<String>.getClass() returns the
same value as the method Vector<Integer>.getClass(). The class information, obtained at runtime
for all objects of a generic class, is the same. This is because, at the time of compilation, the
compiler erases all generic information in the source code. As a result, the compiled bytecodes are
completely compatible with the older version of JRE and generic class behaves the same
regardless of the type that may be associated with it.
In JDK 1.5, it is not possible to invoke the instanceof operator on an object of a generic class, to
query about its type. The compiled bytecode does not retain parameter type information of generic
classes, therefore at runtime generic classes do not exist. The instanceof operator verifies if an
object belongs to a particular class at runtime. As a result, calling the instanceof operator with a
generic class throws a compile time error. For example, the following code throws a compile time
exception.
Vector<String> strings = new Vector<String>();
if(strings instanceof Vector<String>)

You should avoid typecasting of generic code. At runtime, all generic code is converted into normal
code. As a result, there does not exist any generic type information which you can typecast. Such
typecasting code raises an unchecked warning at compile time.
In addition, you cannot create arrays of generic types. This generates a compile time error.
However, you can declare arrays, which are generic.

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Using Wildcards
The methods of the classes in the collections framework of JDK1.4 always receive and return an
object of type Object. This allows you to share elements of one collection with other collections. This
may not be directly possible when using generic collections. This is because, in generic collections,
an object of type Collection<String> is not the same as an object of type Collection<Object>. The
Collection<Object> type is an invariant collection of Objects.
To overcome the problem of invariance in objects, generics introduces bounding or constraining of
type parameters. A constraint, or a bound, is created using wildcards in generics.

Working with Wildcards


In a payroll program that calculates the pay of the employees, you can group all the Employee
objects into a Collection object. You can use a class hierarchy for the employees where a Manager
class, Executive class, and Clerk class extends the Employee class.
If you code a method that takes a Collection object as an argument, then this method works in
JDK1.4 but not in JDK 1.5. This is because of the invariance caused by generics. Listing 199
shows a pseudocode that prints the salary of employees:
Listing 199: The Pseudocode for Payroll Program

public abstract class Employee


{
public abstract double calculatePay();
}
public class Manager extends Employee
{
public double calculatePay()
{
//calculate pay for managers here
}
}
public class Executive extends Employee
{
public double calculatePay()
{
//calculate pay for executives here
}
}
public class Clerk extends Employee
{
public double calculatePay()
{
//calculate pay for clerks here
}
}
public class Payroll
{
public static void main(String args[])
{
ArrayList<Manager> managerList = new ArrayList<Manager>();
managerList.add(new Manager(4000, 1500, 800, 500, 1500));
managerList.add(new Manager(4200, 1500, 800, 500, 1700));
printPay();
}
static void printPay(Collection<Employee> e)
{
While(e.hasNext())
{
System.out.println(e.next().calculatePay());
}
}
}

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

14

In the above code, the printPay() method in the Payroll class fails due to the invariance of generics.
if you specify the parameter type as Collection<Object>, the method fails.
JDK 1.5 introduces the <?> notation, which represents an unknown type. Using this notation, you
write a collection of unknown type as Collection<?>. You can use this notation to represent a
collection of any type. You can also specify the upper and lower bounds to the unknown type.
These bounds provide information about the hierarchy of the unknown type to the compiler. The
notation <? extends A> specifies an upper bound, where the unknown type is any subtype of type
A. Similarly, the notation <? super A> specifies a lower bound, where the unknown type is super
type of type A.
Create a program that uses bounded wildcards and modify the printPay() method such that it takes
a lower bound parameter. The printPay method() prints the salary of all objects that are found in the
collection that it receives. The collection object holds objects of type Employee. You use a lower
bound to access these objects that are covariant. Listing 1910 shows the code for the
Employee.java program:
Listing 1910: The Employee Class
public abstract class Employee
{
double basic;
double deductions;
public abstract double calculatePay();
public Employee()
{
basic = 0;
deductions = 0;
}
public Employee(double b, double d)
{
basic = b;
deductions = d;
}
public void setBasic(double b)
{
basic = b;
}
public void setDeductions(double d)
{
deductions = d;
}
public double getBasic()
{
return basic;
}
public double getDeductions()
{
return deductions;
}
}

The above code shows the abstract class Employee. The abstract method calculatePay() in the
Employee class is implemented by the subclasses of this class. Listing 1911 shows the two
subclasses of the Employee class:
Listing 1911: The Manager and Clerk Classes

public class Manager extends Employee


{
double travelAllowance;
double entertainmentAllowance;
double commissions;
public Manager()
{
super();
travelAllowance = 0;
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

15

entertainmentAllowance = 0;
commissions = 0;
}
public Manager(double basic, double deductions, double travelAllowance, double
entertainmentAllowance, double commissions)
{
super(basic, deductions);
this.travelAllowance = travelAllowance;
this.entertainmentAllowance = entertainmentAllowance;
this.commissions = commissions;
}
public void setTravelAllowance(double ta)
{
travelAllowance = ta;
}
public void setEntertainmentAllowance(double ea)
{
entertainmentAllowance = ea;
}
public void setCommissions(double com)
{
commissions = com;
}
public double getTravelAllowance()
{
return travelAllowance;
}
public double getEntertainmentAllowance()
{
return entertainmentAllowance;
}
public double getCommissions()
{
return commissions;
}
public double calculatePay()
{
return ((getBasic() + travelAllowance + entertainmentAllowance + commissions)
getDeductions());
}
}
public class Clerk extends Employee
{
double overtimePay;
public Clerk()
{
super();
overtimePay = 0;
}
public Clerk(double basic, double deductions, double overtimePay)
{
super(basic, deductions);
this.overtimePay = overtimePay;
}
public void setOvertimePay(double otp)
{
overtimePay = otp;
}
public double getOvertimePay()
{
return overtimePay;
}
public double calculatePay()
{
return ((getBasic() + overtimePay) getDeductions());
}
}

In the above code, the Manager and Clerk classes are the subclasses of the Employee class.
These classes override the claculatePay() method in the Employee class. The managers salary
includes components that are not a part of the clerks salary. The Payroll program uses the
Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

16

Employee class and its subclasses to represent the collective payroll information of all employees.
This program uses a collection object to store information about all the employees and process their
salaries. Listing 1912 shows the code for the Payroll program:
Listing 1912: The Payroll Program

import java.util.*;
public class Payroll
{
public static void main(String args[])
{
ArrayList<Manager> managerList = new ArrayList<Manager>();
managerList.add(new Manager(4000, 1500, 800, 500, 1500));
managerList.add(new Manager(4200, 1500, 800, 500, 1700));
managerList.add(new Manager(4000, 1500, 800, 500, 1800));
managerList.add(new Manager(4300, 1500, 800, 500, 1600));
System.out.println("Pay of managers");
printPay(managerList);
ArrayList<Clerk> clerkList = new ArrayList<Clerk>();
clerkList.add(new Clerk(2500, 500, 1000));
clerkList.add(new Clerk(2700, 500, 1200));
clerkList.add(new Clerk(2400, 500, 1300));
clerkList.add(new Clerk(2800, 500, 0));
System.out.println("Pay of clerks");
printPay(clerkList);
}
public static void printPay(List<? extends Employee> e)
{
Iterator<? extends Employee> iter = e.iterator();
while(iter.hasNext())
{
System.out.println(iter.next().calculatePay());
}
}
}

In the above code, the bound for the printPay() is constructed such that all classes that are a
subclass of the Employee class can be passed as a parameter to the printPay() method. As a
result, you can pass a collection containing Manager objects or Clerk objects as parameter to the
printPay() method. Figure 193 shows the output of the payroll program:

Figure 193: The Output of Payroll Program

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

17

Using Generic Methods


Similar to classes and interfaces, methods can also be generic. In Java, any type declaration such
as variables, methods, classes, and interfaces can be generic. For example, a routine such as a
swap function can be generic. As a result, you can implement a number of swap function variants,
such as swapping one element or swapping a range in a data structure.
It is possible to use wildcards and generic methods interchangeably. However, you should prefer
wildcards when you want covariance along with strong typing, while using container classes.
Generic methods are useful when there is a type dependency between the arguments and the
return types of those arguments. You can use wildcards with declaration of any type in Java. You
can also use wildcards with method signatures.
Modify the Payroll program to include a generic method that adds the two employee lists to a
common list. Listing 1913 shows the modified version of the Payroll program, called Payroll2:
Listing 1913: Payroll2 Program

import java.util.*;
public class Payroll2
{
public static void main(String args[])
{
ArrayList<Manager> managerList = new ArrayList<Manager>();
managerList.add(new Manager(4000, 1500, 800, 500, 1500));
managerList.add(new Manager(4200, 1500, 800, 500, 1700));
managerList.add(new Manager(4000, 1500, 800, 500, 1800));
managerList.add(new Manager(4300, 1500, 800, 500, 1600));
ArrayList<Clerk> clerkList = new ArrayList<Clerk>();
clerkList.add(new Clerk(2500, 500, 1000));
clerkList.add(new Clerk(2700, 500, 1200));
clerkList.add(new Clerk(2400, 500, 1300));
clerkList.add(new Clerk(2800, 500, 0));
ArrayList<Employee> empList = new ArrayList<Employee>();
mergeLists(empList, managerList);
mergeLists(empList, clerkList);
System.out.println("Pay of All Employees");
printPay(empList);
}
public static <T> void mergeLists(ArrayList<T> e1, ArrayList<? extends T>
e2)
{
e1.addAll(e2);
}
public static void printPay(List<Employee> e)
{
Iterator<? extends Employee> iter = e.iterator();
while(iter.hasNext())
{
System.out.println(iter.next().calculatePay());
}
}
}

In the above code, the mergeLists() method takes two ArrayList objects as parameters. The code
also shows the use of wildcards along with generic methods. Figure 194 shows the output of the
Payroll2 program:

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Java ReferencePoint Suite

18

Figure 194: The Payroll2 Program

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

Related Topics
For related information on this topic, you can refer to:
Understanding Classes and Objects in Java
Event and Exception Handling in Java

Reprinted for v697039, Verizon

SkillSoft, SkillSoft Corporation (c) 2002, Copying Prohibited

S-ar putea să vă placă și