Java Reference
In-Depth Information
The above code will compile because the compiler is convinced that this statement will not throw a
ClassCastException
at runtime. It knows that the
get()
method returns an object of a type, which is not known to
the
unknownWrapper
variable. No matter what type of object the
get()
method returns, it will always be assignment-
compatible with the
Object
type. After all, all reference types in Java are subtypes of the
Object
type.
Will the following snippet of code compile?
unknownWrapper.set("Hello"); // A compile-time error
unknownWrapper.set(new Integer()); // A compile-time error
unknownWrapper.set(new Object()); // A compile-time error
unknownWrapper.set(null); // OK
Were you surprised by the above snippet of code? You will find out that it is not as surprising as it seems. The
set(T a)
method accepts the generic type argument. This type,
T
, is not known to
unknownWrapper
, and therefore
the compiler cannot make sure that the unknown type is a
String
type, an
Integer
type, or an
Object
type. This is
the reason that the first three calls to
set()
are rejected by the compiler. Why is the fourth call to the
set()
method
correct? A
null
is assignment-compatible to any reference type in Java. The compiler thought that no matter what
type
T
would be in the
set(T a)
method for the object to which
unknownWrapper
reference variable is pointing to, a
null
can always be safe to use. The following is your
printDetails()
method code. If you pass a
null Wrapper
object
to this method, it will throw a
NullPointerException
.
public class WrapperUtil {
public static void printDetails(Wrapper<?> wrapper) {
// Can assign get() return value to Object
Object value = wrapper.get();
String className = null;
if (value != null) {
className = value.getClass().getName();
}
System.out.println("Class: " + className);
System.out.println("Value: " + value);
}
}
■
Using only a question mark as a parameter type (
<?>
) is known as an
unbounded wildcard
. it places no bounds
as to what type it can refer. You can also place an upper bound or a lower bound with a wildcard. i will discuss bounded
wildcards in the next two sections.
Tip
Upper-Bounded Wildcards
Suppose you want to add a method to your
WrapperUtil
class. The method should accept two numbers that are
wrapped in your
Wrapper
objects and it will return their sum. The wrapped objects may be an
Integer
,
Long
,
Byte
,
Short
,
Double
, or
Float
. Your first attempt is to write the
sum()
method as shown:
public static double sum(Wrapper<?> n1, Wrapper<?> n2) {
//Code goes here
}