the mystery of erasure

来源:互联网 发布:ds cloud windows 编辑:程序博客网 时间:2024/05/01 14:52

as you begin to delve more deeply into generics, there are number of things that won't initially make sense. For example, although you can say Arraylist.class, you can't say ArrayList<Integer>.class

the cold truth is:

there is no information about generic parameter types available inside generic code.

thus, you can know things like the identifier of the type parameter and the bounds of generic type--- you just can't know the actual type parameter(s) used to create a particular  instance. This fact, wich is especially frustrating if you're coming from C++, is the most fundamental issue that you must deal with when work with java generics.


Java generic are implemented using erasure. This is means that any specific type information is erasured when you use a generic.. In the generic, the only thing you known is that you are using an object. So List<String> and List<Integer>are, in fact, the same type in run time. Understanding erasure and how you must deal with it will be one of the hurdles you will face when you learn Java generics.


migration compability 

To allay any potential confusion about erasure, you must clearly understand than it is not a language feature. It is a compromise in the implementation of Java generic, necessary because generics were not made of part of the language from the beginning. This compromise will cause you pain, so you need to get used to it and to understand why it is here.

In an erasure-based implementation, generic types are treated as secondclass types that cannot be used in some important contexts. The generic type are present only duing static type checking, after which, every generic type in the program is erasured by replacing it with a non-generic upper bound. For example, type annotations such as List<T> are erased to List, and ordinary type variables are earsed to Object unless a bound is specified.

The core motivation of erasure is that it allow generified cilents to be used with non-generified libraries, and vice versa. This is often called migration compability.

The problem with erasure

So the primary justification for erasure is the transition process from nongenerified code to generified code, and to incorporate generics into the language without breaking existing libraries. Erasure allows existing nonegeneric client code continue to be used without change, until the clients are ready to rewrite the code for generics. This is a noble motivation, because it doesn't break all existing code.

The cost of erasure is significant, Generic types cannot be used in operations that explicitly refer to runtime types, such as casts, instanceof operations, and new expressions. Because all of the type information about the parameters is lost, whenever you're writing generic code, you must constantly be reminding yourselt that it only appears that you have type information about a parameter. So when you write a piece of code like this:

class Foo<T> {    T var;  }  

it appears when you create an instance of Foo:

Foo<Cat> f = new Foo<Cat>(); 

the code in class Foo ought to know that it is now working with Cat. The syntax strongly suggests that the type of T is being substituted everywhere throughout the class. But it isn't, and you must remind youself ,"No,it's just an Object," whenever you write the code for the class.

In addition,erasure and migration compatility mean that the use of generics  is not enforced when you might want it to be.