Generics with class and method

By | February 2, 2016

Generics is an interface or class that can be used with many different types. Following note will describe generics using in class and method in general.

Generic class

Defined with format: class Box <T1, T2, …,Tn> { /*…*/}

Used:  Box<String, Integer, MyClass, MyInterface> box = new Box<String, Integer, MyClass, MyInterface>(“Hello”,1, car, toy)

Noticeable that T type should be any class, interface, or other variable types exclusive of primitive type.

Example 1: A stack implemented with an internal linked structure.

public class Node<E> {
	E item;
	Node<E> next;

	Node() {
		item = null;
		next = null;
	}

	Node(E item, Node<E> next) {
		this.item = item;
		this.next = next;
	}

	boolean end() {
		return item == null && next == null;
	}
}
public class LinkedStack<T> {
	private Node<T> top = new Node<T>();

	public void push(T item) {
		top = new Node<T>(item, top);
	}
	public T pop() { 
		T result = top.item; 
		if(!top.end()) 
		top = top.next; 
		return result; 
	}

	public static void main(String[] args) {
		
		LinkedStack<String> lss = new LinkedStack<String>();
		for (String s : "I love Java".split(" "))
			lss.push(s);
		String s;
		while ((s = lss.pop()) != null)
			System.out.println(s);
	}
}

Output in the console:

Java
love
I

Generic method

Defined with format: public <E> E method (E [] args) { /*…for example..*/ }

Used: String [] a1 = method(String [] args);

Example 2: A method with different parameterized.

import java.util.ArrayList;
import java.util.List;
import java.util.ArrayList;
import java.util.List;

public class GenericMethods {
	// Three arguments which are of a different parameterized type
	public <T> void f(T x, T y, T z) {
		System.out.println(x.getClass().getName());
		System.out.println(y.getClass().getName());
		System.out.println(z.getClass().getName());
	}

	// Generic methods and variable argument lists coexist
	public <T> List<T> makeList(T... args) {
		List<T> result = new ArrayList<T>();
		for (T item : args)
			result.add(item);
		return result;
	}

	public static void main(String[] args) {
		GenericMethods gm = new GenericMethods();
		// String, Integer, and Double variable type
		gm.f("", 1, 1.0);
		// Float, Character, and Class variable type
		gm.f(1.0F, 'c', gm);
		// makeList method with two variable arguments
		List<String> ls = gm.makeList("A", "B");
		System.out.println(ls);
		// makeList method with six variable arguments
		ls = gm.makeList("ABCDEF".split(""));
		System.out.println(ls);
		// Not recommended because they can be ambiguously inferred by compiler
		List<Integer> ls1 = gm.<Integer>makeList(1,2,3);
		System.out.println(ls1);
	}
}

Output in the console:

java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.Character
com.generic.app.GenericMethods
[A, B]
[, A, B, C, D, E, F]
[1, 2, 3]

Generic interface

The same techniques above were true for generic interface.

Example 3: Generic Interface

public interface Generator<T> {
	T next();
}
public class Rice {
	private static long counter = 0;
	private final long id = counter++;
	
	public String toString() {
		return id +" " + getClass().getSimpleName();
	}
}

Create rice type classes extends Rice: LongGrainBrown,MediumGrainBrown,ShortGrainBrown,BrownBasmati,SweetBrown

public class LongGrainBrown extends Rice {
	/* A long, slender kernel */
}
public class MediumGrainBrown extends Rice{
	/* A shorter, wider kernel*/
}
public class ShortGrainBrown extends Rice{
	/*A short, plump, almost round kernel*/
}
public class SweetBrown extends Rice {
	/* Short and plump with a chalky white, opaque kernel */
}
public class BrownBasmati extends Rice {
	/* India is well known */
}

RiceGenerator.java

public class RiceGenerator implements Generator<Rice> {
	// Generic with wildcard is read only
	private Class<?>[] types = { LongGrainBrown.class, MediumGrainBrown.class,
			ShortGrainBrown.class, BrownBasmati.class, SweetBrown.class };
	private static Random rand = new Random(48);
	
	// Constructor
	public RiceGenerator() {
	};
	
	// Next subclass of Rice
	public Rice next() {
		try {
			// Create new random instance from list of classes  
			return (Rice) types[rand.nextInt(types.length)].newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	// Create a convenient fill method
	public static <T> Collection<T> fill(Collection<T> coll, 
                                     Generator<T> gen, int n) {
		for (int i = 0; i < n; i++) {
			coll.add(gen.next());
		}
		return coll;
	}
	
	public static void main(String[] args) {
		Generator<Rice> gen = new RiceGenerator();
		// Generate 3 random items
		for (int i = 0; i < 3; i++)
			System.out.println(gen.next());
		// Generate by fill method
		Collection<Rice> rices = fill(new ArrayList<Rice>(), 
                                           new RiceGenerator(), 3);
		for (Rice rice : rices) {
			System.out.println(rice);
		}
	}
}

Output in the console:

0 BrownBasmati
1 MediumGrainBrown
2 MediumGrainBrown
3 SweetBrown
4 ShortGrainBrown
5 MediumGrainBrown

References:

  1. Bruce Eckel, “Generics”, In Thinking in Java 4th, pp.439-445, Prentice Hall, 2006.
  2. M. Naftalin, and P. Wadler, “Introduction”, In Java Generics and Collections, Chapter 1, O’Reilly, 2007.
  3. Generics, Oracle Java document, Accessed February 02, 2016, https://docs.oracle.com/javase/tutorial/java/generics/types.html.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.