Let’s update our
Box
class to use generics. We’ll first create a generic type declaration by changing the code “public class Box
” to “public class Box<T>
“; this introduces onetype variable, namedT
, that can be used anywhere inside the class. This same technique can be applied to interfaces as well. There’s nothing particularly complex about this concept. In fact, it’s quite similar to what you already know about variables in general. Just think ofT
as a special kind of variable, whose “value” will be whatever type you pass in; this can be any class type, any interface type, or even another type variable. It just can’t be any of the primitive data types. In this context, we also say thatT
is a formal type parameterof theBox
class./** * Generic version of the Box class. */ public class Box<T> { private T t; // T stands for "Type" public void add(T t) { this.t = t; } public T get() { return t; } }As you can see, we’ve replaced all occurrences of
Object
withT
. To reference this generic class from within your own code, you must perform a generic type invocation, which replacesT
with some concrete value, such asInteger
:Box<Integer> integerBox;You can think of a generic type invocation as being similar to an ordinary method invocation, but instead of passing an argument to a method, you’re passing a type argument —
Integer
in this case — to theBox
class itself. Like any other variable declaration, this code does not actually create a newBox
object. It simply declares thatintegerBox
will hold a reference to a “Box
ofInteger
“, which is howBox<Integer>
is read.An invocation of a generic type is generally known as a parameterized type.
To instantiate this class, use the
new
keyword, as usual, but place<Integer>
between the class name and the parenthesis:integerBox = new Box<Integer>();Or, you can put the entire statement on one line, such as:
Box<Integer> integerBox = new Box<Integer>();Once
integerBox
is initialized, you’re free to invoke itsget
method without providing a cast, as inBoxDemo3
:/* * Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ public class BoxDemo3 { public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); integerBox.add(new Integer(10)); Integer someInteger = integerBox.get(); // no cast! System.out.println(someInteger); } }Furthermore, if you try adding an incompatible type to the box, such as
String
, compilation will fail, alerting you to what previously would have been a runtime bug:BoxDemo3.java:5: add(java.lang.Integer) in Box<java.lang.Integer> cannot be applied to (java.lang.String) integerBox.add("10"); ^ 1 errorIt’s important to understand that type variables are not actually types themselves. In the above examples, you won’t find
T.java
orT.class
anywhere on the filesystem. Furthermore,T
is not a part of theBox
class name. In fact during compilation, all generic information will be removed entirely, leaving onlyBox.class
on the filesystem. We’ll discuss this later in the section on Type ErasureAlso note that a generic type may have multiple type parameters, but each parameter must be unique within its declaring class or interface. A declaration of
Box<T,T>
, for example, would generate an error on the second occurrence ofT
, butBox<T,U>
, however, would be allowed.
Type Parameter Naming Conventions
By convention, type parameter names are single, uppercase letters. This stands in sharp contrast to the variable naming conventions that you already know about, and with good reason: Without this convention, it would be difficult to tell the difference between a type variable and an ordinary class or interface name.The most commonly used type parameter names are:
- E – Element (used extensively by the Java Collections Framework)
- K – Key
- N – Number
- T – Type
- V – Value
- S,U,V etc. – 2nd, 3rd, 4th types
You’ll see these names used throughout the Java SE API and the rest of this tutorial.
Generic Types