In computer programming, generalisation is understood to be a noble pursuit and a fundamental tool for achieving reusability, the idea being that a programmer can be more expressive when he has tools that work with many types. You might recognise the effect of generalisation in many interrelated con ]]>

Class class, objects of which are used to create objects of your own classes.You will find that containers are a quite common theme in Java and they can be manifested in very many different forms, however the basic idea is always the same. A container contains variables and setter() and getter() methods to access and manipulate those variables. For example, Java's Stack class represents a last-in-first-out (LIFO) type of container where the last object you put in is the first one you get out. A good example is a magazine clip for an automatic handgun. You will find that such a clip has a sort of spring mechanism that you push down as you load each bullet and pushes up each time you unload one. If we were to try to implement such a mechanism, we might make an abstraction that would allow us to hold bullets in a type of list:- package generics.java; import java.util.ArrayList; class Bullet { private static int count = 0; private final long id = count++; public String toString() { return this.getClass().getSimpleName() + " " + id; } } public class Ammunition<T> extends ArrayList<T> { Class&ltT&gt type; public Ammunition(Class<T> bullet) { type = bullet; } public void put(int size) { for(int i = 0; i < size; i++) { try { add(type.newInstance()); } catch (InstantiationException e) { System.out.println(e); } catch (IllegalAccessException e) { System.out.println(e); } } } } Here, the Ammunition class is a type of ArrayList that can hold any type but in this example will be used to hold Bullet(s). Notice the use of a type tag to enable the retention of type information. A call to the put() method allows us to populate the list with Bullet objects using the Class.newInstance() method. The following linked Stack is a general purpose container that can be used to hold any type including Bullet like so:- package generics.java; public class Stack<T> { private static class Element<E> { E type; Element<E> currentElement; Element() { type = null; currentElement = null; } Element(E aType, Element<E> nextElement) { this.type = aType; this.currentElement = nextElement; } boolean end() { return type == null && currentElement == null; } } private Element<T> topElement = new Element<T>();// End sentinel public void push(T aType) { topElement = new Element<T>(aType, topElement); } public T pop() { T pop = topElement.type; if(!topElement.end()) topElement = topElement.currentElement; return pop; } public static void main(String[] args) { Ammunition<Bullet> bullets = new Ammunition<Bullet>(Bullet.class); bullets.put(7); Stack<Bullet> magazine = new Stack<Bullet>(); Bullet[] holder = new Bullet[bullets.size]; int index = 0; for(Bullet aBullet : bullets) { magazine.push(aBullet); holder[index++] = aBullet; } System.out.print("push(): " + Arrays.asList(holder)); Bullet aBullet; System.out.print("pop(): " + " ["); while ((aBullet = magazine.pop()) != null) if(aBullet.id == 0) { System.out.print(aBullet + "]"); } else { System.out.print(aBullet + ", "); } } } /* Output push(): [Bullet 0, Bullet 1, Bullet 2, Bullet 3, Bullet 4, Bullet 5, Bullet 6] pop(): [Bullet 6, Bullet 5, Bullet 4, Bullet 3, Bullet 2, Bullet 1, Bullet 0] *// In this example, the Stack container uses a nested class Element, to hold instances of particular types in this case Bullet objects. Each call to the push() method creates a new Element that holds a link to the previous Element within it. Calling the pop() method retrieves each element in reverse. Notice the topElementobject also works like an end sentinel to signal when the stack is empty. The most interesting part of this example is how the nested class is used as a linked container

Generic interfaces

You can also use type parameters with interfaces in much the same way as you do with classes. One of my favorite examples is the Fibonacci sequence. A fibonnaci sequence is a sequence of numbers where each subsequent number is a sum of the previous two. We can use a Generator interface to implement an abstraction of the process of generating a sequence of numbers. In the following example, the next() method will perform this function:- package generics.java; interface Generator<T> { T next(); } public class FibonacciSequence { class Sequence implements Generator<Integer> { private int seed = 0; public Integer next() { return funct(seed++); } private int funct(int next) { if(next < 2) return 1; return funct(next - 2) + funct(next - 1); } } public static void main(String[] args) { FibonacciSequence outer = new FibonacciSequence(); FibonacciSequence.Sequence sequence = outer.new Sequence(); for(int i = 0; i < 20; i++) { System.out.print(sequence.next() + " "); } } } /* Output 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 *// In this example, we use an inner class to implement the Generator. The algorithm that produces a fibonacci series is implemented in the funct() method which is in turn called by the implemented next() method. The autoboxing mechanism makes it possible for the int primitive returned by the funct() method to be converted to an Integer object expected by the next() method. To make this class work with the foreach statement, we could use the adapter design pattern to make it iterable like so:- package generics.java; import java.util.Iterator; public class FibonacciAdapter implements Iterable<Integer> { FibonacciSequence outer = new FibonacciSequence(); FibonacciSequence.Sequence sequence = outer.new Sequence() int counter; FibonacciAdapter(int count) { this.counter = count; } @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { @Override public boolean hasNext() {return counter > 0; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public Integer next() { counter--; return sequence.next(); } }; } public static void main(String[] args) { for( Integer next : new FibonacciAdapter(20)) System.out.print(" " + next); } } /* Output 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 *// When you implement the Iterable<T> interface you must implement the iterator() method to return an Iterator<T> over elements of the specified type. In this example, an anonymous class is used to return an Iterator object that implements methods by which you might iterate over a sequence. Notice here that the type parameter is replaced with the actual type over which we need to iterate. Also notice the use of a counter to control the number of iterations. Here is a variation of the same idea this time using a nested class, it really is a matter of design preference:- package generics.java; import java.util.Iterator; public class FibonacciAdapterTwo implements Iterable<Integer> { int counter; FibonacciAdapterTwo(int count) { counter = count; } static class IterableFibonacci implements Iterator<Integer> { FibonacciSequence outer = new FibonacciSequence(); FibonacciSequence.Sequence sequence = outer.new Sequence(); private int counter; public IterableFibonacci(int count) { this.counter = count; } @Override public boolean hasNext() { return counter > 0; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public Integer next() { counter--; return sequence.next(); } }; public Iterator<Integer> iterator() { return new IterableFibonacci(counter); } public static void main(String[] args) { for(Integer next : new FibonacciAdapterTwo(20)) System.out.print(" " + next); } } /* Output 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 *// Note that a nested class by definition has no access to the non-static elements of its enclosing class. To get around this you can create an instance of the nested class in the enclosing class and then pass values through this instance as demonstrated above; or in the alternative, you could choose to make the outer class member variable staticif you find this to be convenient.

Generic methods

Generic type parameters can also be used with methods in a way that makes it possible to vary the method independently of it's class and give the effect of the method being somehow overloaded. To parameterise a method, you place the type parameter in angle brackets before the return type like so:- package generics.java; class ArbitraryType {} public class GenericMethod { public static <T> String overloaded(T aType) { return aType.getClass().getName(); } public static void main(String[] args) { System.out.println(overloaded(new ArbitraryType())); System.out.println(overloaded(2.55)); System.out.println(overloaded("A String type")); System.out.println(overloaded(2.99F)); } } /* Output generics.java.ArbitraryType java.lang.Double java.lang.String java.lang.Float *// Because of the type parameter and type argument, we are able to pass in any type and hence the effect of the method being overloaded. You could of course specify an actual type in place of the type argument to restrict the use of the method to that particular type, but that is what would happen without the type parameter anyway and of course with generics, you can constrain the type parameter by specifying a bound as a way to exercise more control over the how the method is used. Here is container that can be used to generate, hold and iterate over any type, in addition to being able to create generic type generator:- package generics.java; import java.util.Iterator; public class TypeGenerator<T> implements Generator<T>, Iterable<T> { private Class<T> type; private int counter = 0; public TypeGenerator(Class<T> aType){ this.type = aType; } public TypeGenerator(Class<T> aType, int howMany) { this.type = aType; this.counter = howMany; } class IterableGenerator implements Iterator<T> { @Override public boolean hasNext() { return counter > 0; } @Override public T next() { counter--; return (T)TypeGenerator.this.next(); } @Override public void remove() { throw new UnsupportedOperationException(); } } public Iterator<T> iterator() { return new IterableGenerator(); } public T next() { try { return type.newInstance(); } catch (Exception anException) { throw new RuntimeException(anException); } } public static <T> Generator<T> create(Class<T> aType) { return new TypeGenerator<T>(aType); } } Note the create() method returns a non iterable Generator <T> reference only. Here is how to use the class:- package generics.java; public class GenerateTypes { public static void main(String[] args) throws ClassNotFoundException { Generator pGen = TypeGenerator.create(Piano.class); for(int i = 0; i < 9; i++) System.out.print(pGen.next() + " "); System.out.print("\n"); TypeGenerator bullGen = new TypeGenerator<>(Bullet.class, 6); for(Bullet aBullet : bullGen) System.out.print(aBullet + " "); } } /* Output Piano Piano Piano Piano Piano Piano Piano Piano Piano Bullet 0 Bullet 1 Bullet 2 Bullet 3 Bullet 4 Bullet 5 *// In the GenerateTypes class we use two methods to create TypeGenerator objects. The generic create() method returns a Generator reference and therefore is not iterable, however by using the new keyword to create a new TypeGenerator, a fully iterable object that can be used with the foreach method is returned. Generics are a very useful addition no doubt, to the Java programming language, and would seem, to the uninformed at least, to be the result of a logical and painless evolution. However it does possess some peculiarities that betray something of it's rather 'interesting' journey with the Java programming language.