Generics Introduction
Generics provide the ability to create classes, methods and interfaces to be used with different types of data in a type-safe manner. Generics by adding type safety to the code enables bugs to be detected at compile time rather than at run time. This provides stability to the implementation. The Collections Framework is a great example for understanding Generics. Collections classes like Lists and Maps can used in a type-safe manner by using Generics.Generalized classes with Object type
Java has the capability to create generalized classes, method and interfaces by using Object types. Let us consider a quick example of creating a stack class using Object type. In this example, we use an ArrayList of objects to hold the data.package com.sourcetricks.generics; import java.util.ArrayList; import java.util.List; public class ObjectStack { private List<Object> data = new ArrayList<Object>(); public void push(Object item) { data.add(item); } public Object pop() { if ( data.size() > 0 ) { Object val = data.get(data.size()-1); data.remove(data.size()-1); return val; } return null; } }To use this stack our main would something like below. Please note that we need to do the type casting every time we pop an element from the stack. Assuming the intent is to create a stack of String if someone my mistake puts in a integer type then it would result in a ClassCastException. Note that it is not possible to detect these mistakes at compile time. Run-time issues are hard to debug for large projects.
public class JavaGenerics { public static void main(String[] args) { ObjectStack st = new ObjectStack(); st.push("string"); st.push(10); int i = (Integer) st.pop(); String s = (String) st.pop(); } }
Generalized classes with Generic types
Generic types add the type safety that is lacking in the previous example. There is also no need to cast an Object type into the actual data type.
Let us redo the previous example using generic types. A generic class is defined with the format "class name
public class Stack<T> { private List<T> data = new ArrayList<T>(); public void push(T item) { data.add(item); } public T pop() { if ( data.size() > 0 ) { T val = data.get(data.size()-1); data.remove(data.size()-1); return val; } return null; } }To use this stack our main would something like below. Please note when we instantiate the class we specify the concrete type to be used. If we try to add to the stack any type other than String then we would get a compile time error.
public class JavaGenerics { public static void main(String[] args) { Stack<String> st = new Stack<String>(); st.push("string1"); st.push("string2"); String s1 = st.pop(); String s2 = st.pop(); } }
Raw types
A raw type is the name of a generic class or interface without any type arguments. We can rewrite our main as below. This approach again makes the code unsafe and using of raw types should be avoided.public class JavaGenerics { public static void main(String[] args) { Stack st = new Stack(); st.push("string1"); st.push("string2"); String s1 = (String) st.pop(); String s2 = (String) st.pop(); } }
The Diamond
In Java 7, we can replace the type arguments required to invoke the constructor with empty <>. The compiler infers the type from the context. Using <> is called diamond. We can rewrite the previous example as below.public class JavaGenerics { public static void main(String[] args) { Stack<String> st = new Stack<>(); st.push("string1"); st.push("string2"); String s1 = st.pop(); String s2 = st.pop(); } }
Generic methods
Generics can be used with methods as well. We can declare generic methods that uses one or more type parameters.public static <T> boolean myfunc(T a, T b) { if ( a == b ) return true; return false; }
Bounded type parameters
When specifying a type parameter we can specify an upper bound from which all type arguments should be derived. The previous example doesn't make sense for String type. We can restrict the method to be limited to Number type by specifying the superclass as Number.public static <T extends Number> boolean myfunc(T a, T b) { if ( a == b ) return true; return false; }
0 comments:
Post a Comment