我有个问题:如果对一个自定义的泛型如MyType,其中有个方法public List<String> getList(),如果在声明其对象为MyType mt;则List<Number> lilst = mt.getList()不会有错,但是如果声明为MyType<Number> mt;则前面的赋值就会出错,我知道有个raw type会做擦除,但是结果为什么是上面那样?

解决方案 »

  1.   

    代码这样:
    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();//这样编译不会错
      }
    }
    我感觉两个都不应该报错的,但是为什么会有差别?按说编译器都会在编译的时候将类型擦除掉啊
      

  2.   

    List<String>类型的数据不能用List<Number>类型接收。
      

  3.   

    public class MType<Ts>{
      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();//这样编译不会错
      }
    }
      

  4.   

    我知道不能用Number,但是我不知道的是为什么给那个泛型指明类型就会报错,用raw type就不会报错
      

  5.   


    修改如下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();//这样编译不会错
      }
    }
      

  6.   


    修改很容易,这也不是做无聊的事情,按照Java的泛型和raw type擦除机制不能解释这个问题,肯定Java还有其他一些机制我不知道。并且这位仁兄,鲁迅先生的茴香豆的茴字的四种写法,我并不认为是对孔乙己的讽刺。
      

  7.   

    我看了下楼主的程序。
    感觉第一个之所以会报错, 看报错说明就知道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");
      }
    }
      

  8.   

    楼主的期望应该是“两个都应该报错”,而不是“两个都不应该报错”。  public static void main(String args[]){
         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。
      

  9.   

    更正:
      因为java的泛型是在编译做的类型检查 == 因为java的泛型是在编译做的类型检查
      但是第二个没报错呢 == 但是第二个为什么没报错呢