日期:2014-05-20  浏览次数:20766 次

敬请牛人指点,关于泛型的2个问题
一直在看泛型,一直感觉困惑极多,先问两个问题,
List<Integer> li=new ArrayList<Integer>();
List<Number> ln=new ArrayList<Number>();
ln=li; 
说是编译错误...我想问问
1、为什么会出现错误,java5 是怎么处理 这个的?
2、我们通常的多态实现,如下面代码
class A(){};

class a extends A{}
class b extends B{}

class c
{
    A aa=new a();//或 aa=new b();
    doMethod()
    {
       aa.xxx();//假设 xxx()是一个类A的方法,a和b都进行了实现
     }    

}
要是照 泛型的这个规定,以后这样的代码是不是就不能用了?!!!

还有一个就是
List<?> ls=new ArrayList<String>();
ls.add(new String("A"));
编译也会出错,说是 ? 是 通配符 ,不确定里面是什么值,所以不能往里面传入具体值 
这是什么逻辑?不是已经初始化为new ArrayList<String>()了吗?

请大牛们指点指点迷津,谢谢!!!!!

------最佳解决方案--------------------

Java的泛型,做的是“编译时的类型检查”。

1、为什么会出现错误,java5 是怎么处理 这个的?

即使 类型 B 是 类型A 的子类型,那么 List<B> 和 List<A> 也没什么关系,List<B> 也不是 List<A> 的子类型,两种不同的泛型类型赋值就会报错。


还有一个就是
List<?> ls=new ArrayList<String>();
ls.add(new String("A"));
编译也会出错,说是 ? 是 通配符 ,不确定里面是什么值,所以不能往里面传入具体值 
这是什么逻辑?不是已经初始化为new ArrayList<String>()了吗?

关键词是“编译”,编译当然会出错,因为 ls 声明的类型是 List<?> , 编译器只能看到声明的类型。


------其他解决方案--------------------
引用:
raistlic对第二个问题的解释,我觉得明白了一些,但是对第一个问题的解释,我还是不很清楚,我总觉得范型的使用会破坏多态性!!!这是我的个人理解....希望大牛们答疑解惑,谢谢


第一个问题,一个 List<Integer> 类型的对象不能赋值给 List<Number> ln 变量,可以看成是 Java 的泛型规范,如果这条规范被打破的话,泛型的“类型检查”也就出现了漏洞:


// 如果下面这一句能通过编译的话
List<Number> ln = new ArrayList<Integer>();

// ln 声明的类型是 List<Number> , 那么任何 Number 类型都应该能安全的加进去
ln.add(Double.valueOf("1.0")); // runtime exception


泛型变量本身并不继承它们的引用类型的继承关系,这个特性叫做 "invariant",它的反义词是 "covariant",事实上,数组就是 covariant,比如说, String 是 Object 的子类型,所以 String[] 也是 Object[] 的子类型。

所以数组并不能提供可靠的编译时类型检查,其类型检查是在运行时完成的,如果出现问题,它抛出一个运行时异常:


Number[] numbers = new Integer[10];
numbers[0] = Double.valueOf("1.0"); // runtime exception

------其他解决方案--------------------
你说如果 Animal a = new Animal();VS Cat c = new Cat();
a == c么?
还有你的最后一个问题:
List<?> l 表示l 可以存放 Object 及其 Object 下面的类,那不是和泛型的性能违背了么?
泛型的引入是为了让我们在编译的时候能确定存入集合中的类型,所以返回的时候不用因为要“强制类型转换”而失去 Generic 的功能。
要不你用泛型还有什么意义哈···
------其他解决方案--------------------
差不多就是1楼那个说法了,楼主对这些概念有时候没必要钻牛角尖,在实际应用中用了几次之后就会慢慢的懂了。
------其他解决方案--------------------
List<Integer> li=new ArrayList<Integer>();
List<Number> ln=new ArrayList<Number>();
ln=li; 

li跟ln所容纳的元素类型是不一样的,所以会报错

可能你会认为Integer是Number的子类,所以可以将List<Integer>转成List<Number>
其实是错误的.