敬请牛人指点,关于泛型的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<?> , 编译器只能看到声明的类型。
------其他解决方案--------------------
第一个问题,一个 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>
其实是错误的.