jdk1.5提供的泛型好像有bug哦,请看下面的程序:
import java.util.ArrayList;
import java.util.List;public class TryGeneric 
{
public static void main(String[] args) {
 List<Integer> list = new ArrayList();
 list.add(1);
 list.add(2);
 
 new MyGeneric().printAll(list);
}
}class MyGeneric<K,T>
{
public void printAll(List<String> list)
{

}
}printAll方法的参数是List<String>型的,可为什么我还是可以把List<Integer>的引用传入呢?

解决方案 »

  1.   

    下面的代码打印的结果是什么?       List<String> l1 = new ArrayList<String>();       List<Integer> l2 = new ArrayList<Integer>();       System.out.println(l1.getClass() == l2.getClass());或许你会说false,但是那你就错了。它打印出true。因为所有的泛型类型在运行时有同样的类(class),而不管他们的实际类型参数。事实上,泛型之所以为泛型就是因为它对所有其可能的类型参数,它有同样的行为;同样的类可以被当作许多不同的类型。作为一个结果,类的静态变量和方法也在所有的实例间共享。这就是为什么在静态方法或静态初始化代码中或者在静态变量的声明和初始化时使用类型参数申明是不合法的原因。(原文:As consequence, the static variables and methods of a class are also shared among all the instances. That is why it is illegal to refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or initializer of a static variable.)
      

  2.   

    这个了解,泛型是生成bytecode前已经抹掉了,不过这是另一个问题,和我的没什么关系。
    答非所问罗。
      

  3.   

    import java.util.ArrayList;
    import java.util.List;public class Test 
    {
    public static void main(String[] args) {
     List<Integer> inte = new ArrayList();
     List<String> stri = new ArrayList();
     
     System.out.println(inte instanceof List);//list的一个实例
     System.out.println(stri instanceof List);//list的一个实例
     System.out.println(inte.getClass().getName());//类名:Arraylist
     System.out.println(stri.getClass().getName());//类名:Arraylist
     System.out.println(inte.getClass()==stri.getClass());//同一个类
    }
    }因为是同一个类,互相传递当然没有问题··但是当你把一个Integer类型list的传到Sting型list后,get就会报错···
      

  4.   

    public class TryGeneric 
    {
    public static void main(String[] args) {
     List<Integer> list = new ArrayList();
     list.add(1);
     list.add(2);
     
     new MyGeneric().printAll(list);
    }
    }
    list.add(1);
    list.add(2);
    有问题应该是:
    list.add(new Integer(1));
    list.add(new Integer(2));
      

  5.   

    难道这么大个社区没有人能给个说法吗。至于那些说程序有问题的人,我实在不想费口舌解释这些基础问题,到jdk1.5上跑一下就清楚了。
      

  6.   

    学习+职业交流QQ群,欢迎接分,加入.http://community.csdn.net/Expert/topic/4946/4946220.xml?temp=.7922022
      

  7.   

    http://community.csdn.net/Expert/topic/4945/4945837.xml?temp=.6032373在这里
      

  8.   

    因为在java中 List属于对象,凡是对象都是以引用传递的.不知这样回答满意吗?
      

  9.   

    是这样的,在我们用List<String> 的所有methods的时候,其实jre都使用了动态类型转变,但是在我们用户角度上来看,这是隐藏的,
    比如,我们以前要用((String)list.get(0)).charAt(0);
    现在有了List<String)我们就可以直接使用list.get(0);
    在底层的实现中,jre其实还是使用了动态类型转变,只是在编译的时候就检查过了,确定这个转变是正确的。而当你把Product变成Product<T>的时候,这个Product<T>成为了范型。Product这个东西叫做原始形态。而你上面使用了new Product(),编译器本来需要检查这个T,而你并没有提供,这个Product<T>就又成了原始形态,理所当然的,这个范型中的prt(List<String>) 在你使用new Product().prt(list)的时候,也被编译器认做了原始形态。请注意,如果你改成 public void prt(List<String> l) {
    l.get(0).charAt(0);
    System.out.print(l);
    }l.get(0).charAt这行编译器不会有警告。你或许会问,为什么被打回了原始形态,编译器还会承认这行呢?不是应该使用 ((String)l.get(0)).charAt么?那是因为这行本身并没有任何错误。这个类在使用正确的前提下是完全正确的。而你出错的地方在new Product().prt(list);
    所以,编译器只会在编译这行的时候使用这个范类的原始形态
      

  10.   

    呵呵,谢谢kezhu2003(炎阳天) 兄的解答,但即便我不用泛型来定义一个类,在其中的方法中使用泛型来进行类型限制,也还是可以的,如果就因为使用了泛型就不可以了,我还是认为这是java泛型设计的不合理之处。
      

  11.   

    这不是不合理之处,因为1.5刚刚出现没多久,所以很多以1.4形式的语句都暂时被允许了。比如上面的情况,如果List()被禁止,那么1.4的代码很必须得改正。所以在设计中,为了向下兼容,这种情况会产生警告,但是并不会给禁止
      

  12.   

    public class TryGeneric 
    {
    public static void main(String[] args) {
     List<Integer> list = new ArrayList();
     list.add(new Integer(1));
                       list.add(new Integer(2));  
     new MyGeneric().printAll(list);
    }
    }class MyGeneric
    {
    public void printAll(List<? extends Integer> list)
    {

    }
    }
    java的泛型差c#差远了.
      

  13.   

    import java.util.ArrayList;
    import java.util.List;public class TryGeneric 
    {
    public static void main(String[] args) {
     //原来的
     //List<Integer> list = new ArrayList();
     //修改后的
     List<Integer> list = new ArrayList<Integer>();
     list.add(1);
     list.add(2);
     
     new MyGeneric().printAll(list);
    }
    }class MyGeneric<K,T>
    {
    public void printAll(List<String> list)
    {}
    }这样一改,你再试试看呢,相信大家都知道我说的是什么意思了,不再多讲废话了
      

  14.   

    不是吧,我都明确指定了List<String>,如果你说一个List引用可以通过编译,没有问题,地球人都知道,关键是List<Integer>就不该通过了,不然还有啥意义列。
      

  15.   

    楼主看一下下面的教程就明白了http://java.sun.com/docs/books/tutorial/extra/generics/legacy.html至于设计是否合理,教程里也有说明原因(So, shouldn't this be an error? Theoretically speaking, yes;),如果不是修改以前的代码的话,最好不要使用这种混合的写法。
    ------------------------------------------------------------------------
    呵呵,谢谢kezhu2003(炎阳天) 兄的解答,但即便我不用泛型来定义一个类,在其中的方法中使用泛型来进行类型限制,也还是可以的,如果就因为使用了泛型就不可以了,我还是认为这是java泛型设计的不合理之处。
    ------------------------------------------------------------------------So, shouldn't this be an error? Theoretically speaking, yes; but practically speaking, if generic code is going to call legacy code, this has to be allowed. It's up to you, the programmer, to satisfy yourself that in this case, the assignment is safe because the contract of getAssembly() says it returns a collection of Parts, even though the type signature doesn't show this.
      

  16.   

    我觉得上面那篇文章并没有直接解释楼主提出的问题。当你定义了一个方法 printAll(List<String> list),这里的形参是 List<String> 类型的,那么,如果你用一个 List<Integer> 的实参去调用 printAll 的话,编译器会报错,这是应该的,事实上编译器就是这么做的,但前提是这个 method 是定义在一个“普通”的 class 里。如果这个 method 是定义在一个泛型的 class 里的话,编译器就不报错了,这就是编译器的疏漏了,它完全有能力报个错出来,而且这种情况也不属于“向旧版本程序妥协”的范围呀。
      

  17.   

    C:\Documents and Settings\Shutrazh>java -version
    java version "1.6.0-beta2"
    Java(TM) SE Runtime Environment (build 1.6.0-beta2-b86)
    Java HotSpot(TM) Client VM (build 1.6.0-beta2-b86, mixed mode, sharing)C:\Documents and Settings\Shutrazh>javac TryGeneric.java
    注意:TryGeneric.java 使用了未经检查或不安全的操作。
    注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。C:\Documents and Settings\Shutrazh>javac -Xlint:unchecked TryGeneric.java
    TryGeneric.java:7: 警告:[unchecked] 未经检查的转换
    找到: java.util.ArrayList
    需要: java.util.List<java.lang.Integer>
     List<Integer> list = new ArrayList();
                          ^
    TryGeneric.java:11: 警告:[unchecked] 对作为普通类型 MyGeneric 的成员的 printAll
    (java.util.List<java.lang.String>) 的调用未经检查
     new MyGeneric().printAll(list);
                             ^
    2 警告
      

  18.   

    new MyGeneric<String>().printAll(list);
    创建对象的时候带上 泛型,是可以检查出pringAll(list);的错误的。
    而且楼主的程序
    在这样实现printAll()方法,并运行时,会抛一个类型转换异常。
    java.lang.ClassCastException: java.lang.Integer但是我这个结果并没有解决楼主的问题
      

  19.   

    To:maquan('ma:kju)当你定义了一个方法 printAll(List<String> list),这里的形参是 List<String> 类型的,那么,如果你用一个 List<Integer> 的实参去调用 printAll 的话,编译器会报错,这是应该的,事实上编译器就是这么做的,但前提是这个 method 是定义在一个“普通”的 class 里。
    --------------------------------------------------------
    因为是“普通”类,所以编译器不会把泛型的作用域设定为整个类,如果类中有使用到泛型的方法,那编译器自然会使用泛型规则来进行验证。如果这个 method 是定义在一个泛型的 class 里的话,编译器就不报错了,这就是编译器的疏漏了,它完全有能力报个错出来,而且这种情况也不属于“向旧版本程序妥协”的范围呀。
    --------------------------------------------------------
    但是,如果是“泛型”类,编译器就会把泛型的作用域设定为整个类,如果在声明对象时没有应用泛型说明,编译器就认为程序员不使用新的泛型功能,以至于类中使用到泛型的方法也会被忽略。new MyGeneric().printAll(list);// 泛型被忽略
    new MyGeneric<Class1, Class2>().printAll(list);// 泛型被采用,这时候list的类型要与printAll中的类型完全匹配
      

  20.   

    多谢 rcom10002(KNIGHTRCOM),你解释的很详细,也很有说服力,Sun 的编译器似乎就应该是按照这个逻辑在工作的  :D但我还是认为(有点固执,hehe),当我定义了一个泛型类,却按原始类型使用它的话,并不*一定*表示我要“不使用新的泛型功能”,毕竟我用的实参还是泛型的呀。我想,如果在这种情况下,编译器能够报一个错出来,应该是更恰当的。不知老兄是否同意?
      

  21.   

    class MyGeneric<K,T>改为class MyGeneric好象可以了
      

  22.   

    import java.util.ArrayList;
    import java.util.List;public class TryGeneric 
    {
    public static void main(String[] args) {
     List<Integer> list = new ArrayList<Integer>();
     list.add(1);
     list.add(2);
     
     printAll(list);
    }
    static public void printAll(List<String> list)
    {
         
    }
    }
    这样写就会报错了。
    如果象你那样把方法放在另一个类中是不会报错的。
    原因如下:
    如果你放在一个类中 编译器当然要先检查下用户定义的范行和使用方法的范行是匹配的 否者报错。
    如果你放在两个类中,类检查前则必须先编译,大家应该知道类型擦除吧。结果
    List<Object> list = new ArrayList();
    public void printAll(List<Object> list);
    都要用Object类 代替用户所写的规定类型。
    这时候编译器再检查 就检查不出问题了,因为都是Object了(其实还是有别的方法可以来限制T的 不过默认的话就是转成Object类的,不过你这没用到)他会给出一个警告也就是下面这个
    注意: F:\work\mywork\TEST\TryGeneric.java 使用了未经检查或不安全的操作。
    注意: 要了解详细信息,请使用 -Xlint:unchecked 重新编译。Process completed.接下来检查这步骤只能用户来负责了;SUN 公司之所以把编译器做成这样目的是为了能够与范行以前的代码兼容,因此不要把他认为是类型擦除是正常程序的一部分,以为它本身就是个冒险的尝试
      

  23.   

    List<Integer> list = new ArrayList();
    是泛型吗?
    好好看看。