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