Monday, October 3, 2011

Java Generics Part - 2


Writing Generic Classes
Let us see how to create our own classes using Generics. Let us keep the purpose of the class as simple as holding some Object, the Object Holder class. This Object Holder class can hold any type of Java object. It provides method for getting and setting the current Object. The following shows the class declaration of the Object Holder class.
ObjectHolder.java
package generics.classes;

public class ObjectHolder<O>
{
    private O anyObject;
       
    public O getObject()
    {
        return anyObject;
    }
       
    public void setObject(O anyObject)
    {
        this.anyObject = anyObject;
    }
       
    public String toString()
    {
        return anyObject.toString();
    }
}
Note the following syntax,
public class ObjectHolder<O>
The above statement essentially says that we wish to make the Object Holder class as a Generic Class. Technically, Object Holder is now a parametric class and O is called a type parameter. O serves as a place-holder for holding any type of Object. Note the usage of the type parameter within the class declaration. Now, the clients can use the above class by substituting any kind of object for the place-holder O. Consider the following Client program that makes use of the Object Holder class.
ObjectHolderClient.java
package generics.classes;

import java.net.URL;

public class ObjectHolderClient
{
    public static void main(String[] args) throws Exception
    {
        ObjectHolder<String> stringHolder =
            new ObjectHolder<String>();
        stringHolder.setObject(new String("String"));
        System.out.println(stringHolder.toString());
              
        ObjectHolder<URL> urlHolder = new ObjectHolder<URL>();
        urlHolder.setObject(new URL("http://www.javabeat.net"));
        System.out.println(urlHolder.toString());
    }
}
Note how the Clients instantiates an instance for the Object Holder class.
ObjectHolder<String> stringHolder = new ObjectHolder<String>();
This is called type substitution. For the type parameter O, the type String is substituted. And now the calls to ObjectHolder.setObject(O anyObject) and O ObjectHolder.getObject() can be imagined as ObjectHolder.setObject(String anyObject) and String ObjectHolder.getObject().
Now, let us see another example of Generic classes having two or more parametric types. Assume that we want to represent a class that holds a Composite object along with the elements of the composite object. We can see this kind of Composiste – children relation-ship in a number of places. For example, a Folder containing multiple files or a Window containing a number of UI Components and so on.
Following is the representation of the Container With Elements (ContainerWithElements) class holding a Container object with its children. Note that the class typed parameters have the names Container and Elements respectively for holding the Container object and its child elements.
ContainerWithElements.java
package generics.classes;

import java.util.List;

public class ContainerWithElements<Container, Elements>
{
    private Container outerObject;
    private List<Elements> innerObjects;
       
    public ContainerWithElements(Container outerObject, List<Elements> innerObjects)
    {
        this.outerObject = outerObject;
        this.innerObjects = innerObjects;
    }
       
    public Container getOuterObject()
    {
        return outerObject;
    }
       
    public void setOuterObject(Container outerObject)
    {
        this.outerObject = outerObject;
    }
       
    public List<Elements> getInnerObjects()
    {
        return innerObjects;
    }
       
    public void setInnerObjects(List<Elements> innerObjects)
    {
        this.innerObjects = innerObjects;
    }
       
}            

The Client program that makes use of the above class is given below. Note the usage of the classes Folder, File, Window and Button are from the generics.classes package and they have nothing to do with the genuine java.* classes.
ContainerWithElementsClient.java
package generics.classes;

import java.util.Arrays;

public class ContainerWithElementsClient
{
    public static void main(String[] args)
    {
        ContainerWithElements<Folder, File> folderWithFiles
            = new ContainerWithElements<Folder, File>(
                new Folder(), Arrays.asList(new File(), new File()));
              
        ContainerWithElements<Window, Button> windowWithButtons
            = new ContainerWithElements<Window, Button>(
                new Window(), Arrays.asList(new Button(), new Button()));
    }
}
For code completeness, the declaration of the classes Folder, File, Window and Button is given below.
class Folder{}
class File{}

class Window{}
class Button{}


No comments: