Raw
Types and Legacy Code
Because support for generics
did not exist prior to JDK 5, it was necessary to provide some transition path
from old, pre-generics code. At the time of this writing, there is still
pre-generics legacy code that must remain both functional and compatible with
generics. Pre-generics code must be able to work with generics, and generic
code must be able to work with pre-generics code.
To handle the transition to
generics, Java allows a generic class to be used without any type arguments.
This creates a raw type for the
class. This raw type is compatible with legacy code, which has no knowledge of
generics. The main drawback to using the raw type is that the type safety of
generics is lost.
Here is an example that shows
a raw type in action:
// Demonstrate a raw type.
class Gen<T> {
T ob; // declare an object of type T
//Pass the constructor a reference to an object
of type T.
Gen(T o) { ob = o;
}
// Return ob.
T getob() { return ob;
}
}
// Demonstrate raw type.
class RawDemo {
public static void main(String args[]) {
// Create a Gen object for Integers.
Gen<Integer> iOb = new
Gen<Integer>(88);
// Create a Gen object for Strings.
Gen<String> strOb = new
Gen<String>("Generics Test");
Create a raw-type Gen object and give it
a Double value.
Gen raw = new Gen(new Double(98.6));
//Cast here is necessary because type is
unknown.
double d = (Double) raw.getob();
System.out.println("value: " + d);
//The use of a raw type can lead to run-time exceptions.
Here are some examples.
//The following cast causes a run-time error!
int i = (Integer) raw.getob(); // run-time
error
//This assignment overrides type safety.
strOb = raw; // OK, but potentially wrong
String str = strOb.getob(); // run-time error
//This assignment also overrides type safety.
raw = iOb; // OK, but potentially wrong
d = (Double) raw.getob(); // run-time error
}
}
This program contains several
interesting things. First, a raw type of the generic Gen class is created by the following declaration:
Gen raw = new Gen(new Double(98.6));
Notice that no type arguments
are specified. In essence, this creates a Gen
object whose type T is replaced by Object.
A raw type is not type safe.
Thus, a variable of a raw type can be assigned a reference to any type of Gen object. The reverse is also
allowed; a variable of a specific Gen
type can be assigned a reference to a raw Gen
object. However, both operations are potentially unsafe because the type
checking mechanism of generics is circumvented.
This lack of type safety is
illustrated by the commented-out lines at the end of the program. Let’s examine
each case. First, consider the following situation:
int i = (Integer) raw.getob(); // run-time
error
In this statement, the value
of ob inside raw is obtained, and this value is cast to Integer. The trouble is that raw
contains a Double value, not an
integer value. However, this cannot be detected at compile time because the
type of raw is unknown. Thus, this
statement fails at run time.
The next sequence assigns to a strOb (a reference of type Gen<String>) a reference to a raw
Gen object:
strOb = raw; // OK, but potentially wrong
// String str = strOb.getob(); // run-time error
The assignment, itself, is
syntactically correct, but questionable. Because strOb is of type Gen<String>,
it is assumed to contain a String.
However, after the assignment, the object
referred to by strOb contains a Double. Thus, at run time, when an
attempt is made to assign the contents of strOb
to str, a run-time error results
because strOb now contains a Double. Thus, the assignment of a raw
reference to a generic reference bypasses the type-safety mechanism.
The following sequence
inverts the preceding case:
raw = iOb; // OK, but potentially wrong
d = (Double) raw.getob(); // run-time error
Here, a generic reference is
assigned to a raw reference variable. Although this is syntactically correct,
it can lead to problems, as illustrated by the second line. In this case, raw now refers to an object that
contains an Integer object, but the
cast assumes that it contains a Double. This error cannot be prevented
at compile time. Rather, it causes a run-time error.
Because of the potential for
danger inherent in raw types, javac
displays unchecked warnings when a raw type is used in a
way that might jeopardize type safety. In the preceding program, these lines generate unchecked warnings:
Gen raw = new Gen(new Double(98.6));
strOb = raw; // OK, but potentially wrong
In the first line, it is the
call to the Gen constructor without
a type argument that causes the warning. In the second line, it is the
assignment of a raw reference to a generic variable that generates the warning.
At first, you might think
that this line should also generate an unchecked warning, but it does not:
raw = iOb; // OK, but potentially wrong
No compiler warning is issued
because the assignment does not cause any further
loss of type safety than had already occurred when raw was created.
One final point: You should
limit the use of raw types to those cases in which you must mix legacy code
with newer, generic code. Raw types are simply a transitional feature and not
something that should be used for new code.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.