术语“类型擦除”并不能真正正确地描述Java在泛型方面的问题。
类型擦除本身并不是一件坏事,事实上,它对于性能来说是非常必要的,并且经常在c++、Haskell、D等语言中使用。
在你厌恶之前,请回忆一下维基百科上对字体擦除的正确定义
什么是类型擦除?
类型擦除是指在程序在运行时执行之前,从程序中删除显式类型注释的加载时过程
Type erasure means to throw away type tags created at design time or inferred type tags at compile time such that the compiled program in binary code does not contain any type tags.
And this is the case for every programming language compiling to binary code except in some cases where you need runtime tags. These exceptions include for instance all existential types (Java Reference Types which are subtypeable, Any Type in many languages, Union Types).
The reason for type erasure is that programs get transformed to a language which is in some kind uni-typed (binary language only allowing bits) as types are abstractions only and assert a structure for its values and the appropriate semantics to handle them.
所以这是回报,很正常的事情。
Java的问题是不同的,是由它如何具体化引起的。
通常认为Java没有具象化泛型的说法也是错误的。
Java确实具体化了,但由于向后兼容,以一种错误的方式。
什么是物化?
从维基百科
具象化是将关于计算机程序的抽象思想转化为用编程语言创建的显式数据模型或其他对象的过程。
物化是指通过专门化将抽象的东西(参数类型)转化为具体的东西(具体类型)。
我们用一个简单的例子来说明这一点:
有定义的数组列表:
ArrayList<T>
{
T[] elems;
...//methods
}
是一个抽象,具体来说是一个类型构造函数,当特化一个具体类型时,它会被“具体化”,比如Integer:
ArrayList<Integer>
{
Integer[] elems;
}
其中ArrayList<Integer>是一个真正的类型。
但这正是Java所不具备的!!相反,它们不断具象化抽象类型及其边界,即产生相同的具体类型,独立于为专门化传递的参数:
ArrayList
{
Object[] elems;
}
这里用隐式绑定对象具体化(ArrayList<T extends Object> == ArrayList<T>)。
尽管它使泛型数组不可用,并导致原始类型的一些奇怪错误:
List<String> l= List.<String>of("h","s");
List lRaw=l
l.add(new Object())
String s=l.get(2) //Cast Exception
它会引起很多歧义
void function(ArrayList<Integer> list){}
void function(ArrayList<Float> list){}
void function(ArrayList<String> list){}
参考相同的函数:
void function(ArrayList list)
因此,在Java中不能使用泛型方法重载。