我有个问题:如果对一个自定义的泛型如MyType,其中有个方法public List<String> getList(),如果在声明其对象为MyType mt;则List<Number> lilst = mt.getList()不会有错,但是如果声明为MyType<Number> mt;则前面的赋值就会出错,我知道有个raw type会做擦除,但是结果为什么是上面那样?
解决方案 »
- 急 求高手给与解答 不能正常显示
- 在JAVA中如何用语句打开一个文档??
- equal
- Vector中的indexOf用法
- Final成员变量的问题?
- 我的导师给我出了一个论文题目《java多线程技术探讨》
- 求大神改改代码,小弟实在没有办法了,就是N个人站一圈,报数从1开始报到3的人退出。答案看过了,但是不清楚自己的哪里错了,求批改
- 用Java编写的一个小Applet为什么不能在NetCaptor浏览器中显示?
- 最简单的小Applet,在jb中可以运行,离开JB环境后在IE和DOS中就不能运行的问题?
- 这两道题比较类似,请高手解答(YY)
- Java Applet小应用程序,用IE无法查看html文件,求帮助
- jframe中移除组件
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的泛型是在编译期做的类型检查
但是第二个没报错呢 == 但是第二个为什么没报错呢