我有个问题:如果对一个自定义的泛型如MyType,其中有个方法public List<String> getList(),如果在声明其对象为MyType mt;则List<Number> lilst = mt.getList()不会有错,但是如果声明为MyType<Number> mt;则前面的赋值就会出错,我知道有个raw type会做擦除,但是结果为什么是上面那样?
调试欢乐多
public Class MType<T>{
public List<String> getList(){
return null;
}
public static void main(String args[]){
MType<Number> ty= new MType();
List<Number> l = ty.getList();//这样编译会报错
MType ty2= new MType();
List<Number> l = ty2.getList();//这样编译不会错
}
}
我感觉两个都不应该报错的,但是为什么会有差别?按说编译器都会在编译的时候将类型擦除掉啊
public List<String> getList(){
return null;
}
public static void main(String args[]){
MType<Number> ty= new MType();
List<String> l = ty.getList();//这样编译也不会错 这里好像不能用<Number>
MType ty2= new MType();
List<Number> l1 = ty2.getList();//这样编译不会错
}
}
修改如下public Class MType<T>{
public List<Object> getList(){
return null;
}
public static void main(String args[]){
MType<Number> ty= new MType();
List<Number> l = ty.getList();//这样编译会报错
MType ty2= new MType();
List<Number> l = ty2.getList();//这样编译不会错
}
}
修改很容易,这也不是做无聊的事情,按照Java的泛型和raw type擦除机制不能解释这个问题,肯定Java还有其他一些机制我不知道。并且这位仁兄,鲁迅先生的茴香豆的茴字的四种写法,我并不认为是对孔乙己的讽刺。
感觉第一个之所以会报错, 看报错说明就知道List<String>不能转化为List<Number>,这种报错会在编译阶段就查明。
第二个以所以没有报错,是和java的编译机制有关系。 第二个这种情况因为T没有具体的class类型, 这种问题会在执行阶段出错, 这种未初始化T的声明类型check不会在编译阶段check,而是推迟到执行阶段。其实这种情况和原来的没有加泛型的时候一样, 要等到取具体的元素时进行类型转换。
试着看看下面的代码。import java.util.ArrayList;
import java.util.List;public class MyType<T>{
public ArrayList<String> getList(){
ArrayList<String> temp = new ArrayList<String>();
temp.add("checked");
return temp;
}
public static void main(String args[]){
MyType<Number> ty= new MyType();
//ArrayList<Number> l = ty.getList();//这样编译会报错
MyType ty2= new MyType();
List<Number> l1 = ty2.getList();//这样编译不会错
Number st = l1.get(0);
System.out.println(l1.size() > 0? l1.get(0):" no value");
}
}
MType<Number> ty= new MType();
List<Number> l = ty.getList();//(1)这样编译会报错
MType ty2= new MType();
List<Number> l = ty2.getList();//(2)这样编译不会错
}
1,2两句在编译的时候应该都是要报错的(List<String> = List<Number>),因为java的泛型是在编译器做的类型检查,编译后把类型信息“擦除”了。但是第二个没报错呢。原因在JSL中已经说明白了,原文如下:The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static
field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces
is the erasure of its type in the generic declaration corresponding to C.
The type of a static member of a raw type C is the same as its type in the generic
declaration corresponding to C.尤其看红色部分,就是说一个没有超类的原生类型C,他的构造器,实例方法或非静态域M的类型是所声明的泛型对应的擦除类型。 MType ty2= new MType();
List<Number> l = ty2.getList();//(2)类中实例方法getList()的返回类型是List<String>,但是MType ty2是个raw type,此时按照JSL的描述,这个实例方法的返回类型应该是List<String>对应的擦除类型,也就是List,所以List<Number> list = List,这样的代码只会给出一个unchecked警告,而不是个error。
因为java的泛型是在编译器做的类型检查 == 因为java的泛型是在编译期做的类型检查
但是第二个没报错呢 == 但是第二个为什么没报错呢