120 likes | 282 Views
Creating Generic Classes. Introduction. Java Generics were added to allow for type-safe collections and eliminate the need for burdensome, code-cluttering casts when working with collections. ArrayList list = new ArrayList (); l ist.add(“foo ”);
E N D
Introduction • Java Generics were added to allow for type-safe collections and eliminate the need for burdensome, code-cluttering casts when working with collections. ArrayList list = new ArrayList(); list.add(“foo”); String e = (String) list.get(0);// cast is annoying Integer e = (Integer)list.get(0); //runtime error!
Generics • Many Java classes (including all Collections) were retrofitted to use generic types as: ArrayList<String> slist= new ArrayList<String>(); slist.add(“hello”); //compiler can check! String s = slist.get(0); //no cast required • This is read as “An ArrayList of String”. • Obviously, any object can be used, String just an example.
Autoboxing • The native datatype wrapper classes (Integer, Double, Float, etc.) have a special property when used with generics. LinkedList<Integer> list = new LinkedList<Integer>(); list.add(3); //new Integer(3) not necessary! inti = list.get(0); //returns a native int This feature saves wrapping and unwrapping native types. It is separate from but goes hand in hand with generics.
Some gotchas • This is all pretty simple – using classes built on generics not much harder than using classes based on Object. • There are a few gotchas though even at list level. The most common are: • instanceof will not work with parameterized types • arrays of parameterized types are illegal • E.g. ArrayList<String>[] list = new ArrayList<String>[3]; //NO!
View from the other side • Sometimes you might need to create your own generic classes. • This is considered a bit more of an advanced topic, but everyone should be familiar with the basics. • We go into much more detail in Advanced Java.
** * Generic version of the Box class. * @param <T> the type of value being boxed */ public class Box<T> { private T t; // T stands for "Type" public void add(Tt) { this.t = t; } public T get() { return t; } } Using Box<T> signals that users can create Boxes of any type. it is also possible to have generic methods within classes that themselves are not Generic.
Using the Box class class BoxDemo3 { public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); //as of 1.7 ok to use Box<Integer> i = new Box(); integerBox.add(new Integer(10)); Integer someInteger = integerBox.get(); // no cast! intsomeIntegerAsNativeType = integerBox.get(); //autoboxing System.out.println(someInteger); } }
public class Box<T> { private T t; public void add(Tt) { this.t = t; } public T get() { return t; } public <U> void inspect(Uu){ System.out.println("T: " + t.getClass().getName()); System.out.println("U: " + u.getClass().getName()); } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); integerBox.add(new Integer(10)); integerBox.inspect("some text"); } } Generic type parameters for methods Signals that the method takes a generic type parameter (U by convention). u is of type U
public class Box<T> { private T t; public void add(Tt) { this.t = t; } public T get() { return t; } public <U extends Number> void inspect(Uu){ System.out.println("T: " + t.getClass().getName()); System.out.println("U: " + u.getClass().getName()); } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); integerBox.add(new Integer(10)); integerBox.inspect("some text"); // error: this is still String! } } Bounded type parameters. Read as “anything that extends Number”. Float ok but String not, e.g.
A couple of more gotchas • You cannot instantiate type variables! T obj = new T(); //NO This can be worked around with reflection but it is really ugly. Consider other alternatives. • You cannot throw or catch instances of a generic class