您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

Java中泛型的协变

2024/6/21 15:28:38发布31次查看
在工作中遇到一个问题,用代码描述如下:
package test;import java.util.linkedlist; import java.util.list;public class listtest { public void func(list<base> list) { } public static void main(string args[]) { listtest lt = new listtest(); list<derived> list = new linkedlist<derived>(); lt.func(list); // 编译报错 } }class base { }class derived extends base { }
这里需要写一个函数func,能够以base的list作为参数。原以为传一个derived的list也可以,因为derived是base的派生类,那derived的list也应当是base的list的派生类,结果编译器报错。
究其原因,在网上查了一些资料:java的泛型并非协变的。
泛型的协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型。
例如c#中的泛型就是支持协变的:
ienumerable<derived> d = new list<derived>(); ienumerable<base> b = d;
但是java的泛型却是不支持协变的,类似上面的代码在java中无法通过编译。
但有趣的是,java中的数组却是支持协变,例如:
integer[] intarray = new integer[10]; number[] numberarray = intarray;
总结:java的泛型不支持协变,更多的是从类型安全的角度考虑。这种设计不是一定必须的,例如c#就没有采用这种设计。只能说java的设计者在易用性和类型安全之间做了取舍。
最后回到最初的那个问题,要实现一个那样的方法func,可以修改为:
public void func(list list) { }
或者采用参数化类型:
public <t> void func(list<t> list) { }
但是这样也有问题,会模糊了func的参数类型。更好的办法是不改func,在传参时就传一个base类型的list,这就要求在将元素加入这个list时就要转型成base类型。
ps:通过限制参数类型:
public void func(list<? extends base> list) { }
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product