Recently I had to do portlet coding from scratch and refreshed some of JAVA basics and one of that is "Generics" (To get more clarity around difference between Map<String, ?> and Map<String, Object>)
Generics
are much like the more familiar formal parameters used in method declarations. The difference is that the inputs
to formal parameters are values, while the inputs to type parameters are types
public
class Box {
private Object object;
private Object object;
public
void set(Object object) { this.object = object; }
public Object get() { return object; }
}
public Object get() { return object; }
}
Can write as below
using the generics
public
class Box<T> {
// T stands for "Type"
private T t;
// T stands for "Type"
private T t;
public void set(T t) { this.t = t;
}
public T get() { return t; }
}
public T get() { return t; }
}
A type
variable can be any non-primitive type you specify: any class type, any
interface type, any array type, or even another type variable.
You can use any
letter (you can use 'X' instead of 'T' in above example) or letter combination
, but by convention and to avoid confustion between the actual type , type
parameter names are single and uppercase letters.
E - Element (used
extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
Type Parameter , eg:
public class Box<T> , here 'T' is type parameter
Type Argument, eg:
Box<Integer> a=new Box<Integer>(); , here 'Integer' is type
argument
Multiple
type parameters
Generic classes can
also have multiple type parameters ( you can also substitute type parameter
with parameterized type)
public
class Order<K, V>{
K key;
V value;
}
Order<String,
Box<String>> boxOder = new Order<String, Box<String>();
NOTE:
In Java SE 7 and
later, you can replace the type arguments required to invoke the constructor of
a generic class with an empty set of type arguments (<>) as long as the
compiler can determine. This pair of angle brackets, <>, is informally called
the diamond. For example, you can create an instance of Box<Integer> with
the following statement:
Box<Integer>
integerBox = new Box<>();
RawType
Assume you have
generic class definition as below
public
class Box<T> {
// T stands for "Type"
private T t;
// T stands for "Type"
private T t;
public void set(T t) { this.t = t;
}
public T get() { return t; }
}
public T get() { return t; }
}
You can
create the object like
Box
rawBox = new Box(); //It compiles and
runs fine but it gives you java warning. This is just backward compatibility.
You can
assign parametric object to rawType reference as below
Box<Integer>
box = new Box<>(); //Java7 allows this diamond , by default it considers
as Box<Integer>
Box
rawBox = box;
Generic
Methods
Generic methods are
methods that introduce their own type parameters. This is similar to declaring
a generic type, but the type parameter's scope is limited to the method where
it is declared.
class Util{
public
static <K,V> boolean compare(Order<K,V> order1, Order<K,V>
order2){
return
order1.getKey().equals(order2.getKey()) &&
order1.getValue().equals(order2.getValue());
}
}
//Generic Methods
Order<Integer,
String> order1 = new Order<Integer, String>(1111,"First
Order");
Order<Integer,
String> order2 = new Order<Integer, String>(2222,"Second
Order");
Util.<Integer,
String>compare(order1, order2);
Util.compare(order1,
order2); //you can also ignore/remove
the parameterized the type while calling the method.
Bounded
Parameters (using extends in generics)
There may be times
when you want to restrict the types that can be used as type arguments in a
parameterized type. To declare a bounded type parameter, list the type
parameter's name, followed by the extends keyword, followed by its upper bound
. Extends is used in a general sense to mean either "extends" (as in
classes) or "implements" (as in interfaces).
//Generics Extends
List<? extends
Number> testList1 = new ArrayList<Number>();
List<? extends
Number> testList2 = new ArrayList<Integer>();
List<? extends
Number> testList3 = new ArrayList<Double>();
testList2.add(new
Integer(10)); //This is still a error
You can't add any
object to List<? extends T> because you can't guarantee what kind of List
it is really pointing to, so you can't guarantee that the object is allowed in
that List. The only "guarantee" is that you can only read from it and
you'll get a T or subclass of T.
Multiple
Bound Parameter
Type parameter can
have multiple bounds. A type variable with multiple bounds is a subtype of all
the types listed in the bound. If one of the bounds is a class, it must be
specified first.
<T extends B1,
B2, B3>
Generics
inheritance
Box<Integer> is not a subtype of Box<Number> even
though Integer is a subtype of Number. Given two concrete types
A and B (for example, Number and Integer), MyClass<A> has no relationship
to MyClass<B>, regardless of whether or not A and B are related
Wildcard
In generic code, the
question mark (?), called the wildcard, represents an unknown type. The
wildcard can be used in a variety of situations: as the type of a parameter,
field, or local variable; sometimes as a return type (though it is better
programming practice to be more specific). The wildcard is never used as a type
argument for a generic method invocation, a generic class instance creation, or
a supertype.
Upper Bound Wildcard
You can use an upper
bounded wildcard to relax the restrictions on a variable. Upper bounded
wildcard restricts the unknown type to be a specific type or a subtype of that
type and is represented using the extends keyword.
For example, say you
want to write a method that works on List<Integer>, List<Double>,
and List<Number>; you can achieve this by using an upper bounded
wildcard.
To declare an
upper-bounded wildcard, use the wildcard character ('?'), followed by the
extends keyword, followed by its upper bound.
public static void
process(List<? extends Foo> list){ }
Unknown Wildcard
The
unbounded wildcard type is specified using the wildcard character (?), for
example, List<?>. This is called a list of unknown type.
public static void
printList(List<Object> list) {
for (Object elem : list) System.out.println(elem + " ");
}
The goal of
printList is to print a list of any type, but it fails to achieve that goal —
it prints only a list of Object instances; it cannot print List<Integer>,
List<String>, List<Double>, and so on, because they are not
subtypes of List<Object>. To write a generic printList method, use
List<?> .
For any concrete
type A, List<A> is a subtype of List<?>
It's important to
note that List<Object> and List<?> are not the same. You can insert
an Object, or any subtype of Object, into a List<Object>. But you can
only insert null into a List<?>
An instance
of HashMap<String, String> matches Map<String,
?> but not Map<String, Object>
A thing sometimes
misunderstood in Java's generics is that List<String> is not a
subtype of List<Object>. (But String[] is in fact a subtype
of Object[], that's one of the reasons why generics and arrays don't mix
well. (arrays in Java are covariant, generics are not, they
are invariant)).
Lower bound wildcard
lower
bounded wildcard restricts the unknown type to be a specific type or a super
type of that type. A lower bounded
wildcard is expressed using the wildcard character ('?'), following by
the super keyword, followed by its lower bound: <? super A>.
Say you want to
write a method that puts Integer objects into a list. To maximize flexibility,
you would like the method to work on List<Integer>, List<Number>,
and List<Object> — anything that can hold Integer values.
public static void
addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}
Resources
No comments:
Post a Comment