public class Box<T> { // T stands for "Type" protected T t; public void add(T t) { this.t = t; } public T get() { return t; } }As you can see, the type looks like a parameter to a function. You are allowed to pass multiple types to a template. For example, a hash table would have types for both the key and the value objects.
Here is a declaration of a variable of type Box, and its use:
class Test { static public void main(String args[]) { Box<String> b = new Box<String>(); b.add(args[0]); String myArg = b.get(); System.out.println(myArg); } }
Box<String> b = new Box<>();
class Foo { LinkedList<Integer> a = new LinkedList(); Foo() { a.add(3); a.add(6); int x = a.get(0) + a.get(1); } } UNIX> javac Foo.java Note: Foo.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details.If you recompile with -Xlint then the Java compiler will be forthcoming about the fact that you omitted the diamond operator when creating the LinkedList object. Note that the solution is to write:
LinkedList<Integer> a = new LinkedList<>();
public <V> void print(V data[]) { for (V val : data) { System.out.println(val); } }Notice that there is a <V> in front of the void and after the public keywords. If I had instead used T, I would not have been required to use a leading <T>.
When I invoke a generic method, I may or may not have to prefix it with the type of the object I am passing in:
Box b; b.<String>print(args); // always works b.print(args) // usually worksIf you do not prefix the method call with the type of the object you are passing as an argument, then the java compiler will attempt to use type inference to determine the type of the parameter. Usually this will be successful. If the java compiler cannot determine the type and gives you an error message, then you will have to explicitly prefix the method with the type of the object you are passing to it.
public <V extends Comparator<V>> void sort(V data[]){...}
List<Number> myList = new List<Integer>();This code looks like it should compile since Integer is a subclass of Number. However, the java compiler complains and says that List<Integer> is not a subclass of List<Number>. The reason is that myList should be able to store any type of number, such as a floating point number, but by assigning it a list of integers, you have restricted it to storing only integers. Java considers this an impermissable restriction, even though you should be able to perform any operation on the list of integers that you could on the list of numbers. To get around this restriction, you can use upper bounded wildcards, which indicates that a variable can accept an object that contains any subtype of the upper bound. For example the following function sums the numbers in a list and can accept any list whose objects are a subtype of Number:
public static double sumOfList(List<? extends Number> list) { double s = 0.0; for (Number n : list) s += n.doubleValue(); return s; }
You can also use unbounded wild cards, which is a ? followed by nothing else. In the following example, printList accepts a list of any type of object:
public static void printList(List<?> list) { for (Object elem: list) System.out.print(elem + " "); System.out.println(); }
List<? super Integer> myList;In my experience lower bounds never come up while upper bounds do because of the desire to use subclasses in place of superclasses.
public class Box { protected Object t; public void add(Object t) { this.t = t; } public Object get() { return t; } }The Java compiler then inserts downcasts into your code to ensure that the objects get converted to the appropriate type before they are used.
Pair<int, char> p = new Pair<>(8, 'a'); // compile-time errorHowever, the follow declaration is legal because Java will auto box the 8 into an Integer object and the 'a' into a Character object.
Pair<Integer, Character> p = new Pair<>(8, 'a');
public static <E> void append(List<E> list) { E elem = new E(); // compile-time error list.add(elem); }The reason for this restriction is because type erasure will replace E with its upper bound. Hence rather than creating an instance of E, you will create an instance of its upper bound, which is not what you intended.
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time errorThe Java tutorial gives the following example to show why this declaration could prove problematic if it were allowed:
The following code works as you expect:You can work around this problem by using the original "raw type" generics:Object[] strings = new String[2]; strings[0] = "hi"; // OK strings[1] = 100; // An ArrayStoreException is thrown.If you try the same thing with a generic list, there would be a problem:Object[] stringLists = new List<String>[2]; // compiler error, but pretend it's allowed stringLists[0] = new ArrayList<String>(); // OK stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown, // but the runtime can't detect it.If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.
List [] arrayOfLists = new List[2];You can now insert Integers into your lists and downcast them when you remove them.
Another workaround would be to use an ArrayList rather than an array. For example:
import java.util.*; class ListOfLists { public static void main(String args[]) { new ListOfLists(); } public ListOfLists() { ArrayList<ArrayList<String>> myList = new ArrayList<ArrayList<String>>(); myList.add(new ArrayList<String>()); myList.add(new ArrayList<String>()); myList.get(0).add("brad"); myList.get(1).add("yifan"); myList.get(1).add("smiley"); System.out.println("List 1 Contents"); for (String elem : myList.get(0)) { System.out.printf("\t%s%n", elem); } System.out.printf("%nList 2 Contents%n"); for (String elem : myList.get(1)) { System.out.printf("\t%s%n", elem); } } }
struct Node { void *value; struct Node *next; };
#include <stdio.h> #include <string.h> // generic min function void *min(void *element1, void *element2, int (*compare)(void *, void *)) { if (compare(element1, element2) < 0) return element1; else return element2; } // stringCompare downcasts its void * arguments to char * and then passes // them to strcmp for comparison int stringCompare(void *item1, void *item2) { return strcmp((char *)item1, (char *)item2); } int main(int argc, char *argv[]) { if (argc != 3) { printf("usage: min string1 string2\n"); return 1; } // call min to compare the two string arguments and downcast the return // value to a char * char *minString = (char *)min(argv[1], argv[2], stringCompare); printf("min = %s\n", minString); return 0; }