default java 泛型_java中的泛型(二)

上一节我介绍了java中泛型的基本原理和使用,今天我介绍java中泛型类型参数的限定和通配符。在java中,泛型是通过类型擦除实现的,泛型是java编译器的概念,java在运行时对与泛型是一无所知的,了解这一点有助于理解java中泛型的一些令人混淆的地方和局限。

在上一篇文章中我们提到了一个词叫做类型参数。关于这个参数我们了解的不多知识把它看成一个Object对象,在java中支持限定这个参数的上界,也就是说参数必须是给定上界的子类或就是给定的上界类型。这个限定通过关键字extends实现。这个上界可以是某个具体的类或者接口。例如:

public class Generic{

K one;

V two;publicGeneric(K one, V two){this.one =one;this.two =two;

}publicK getOne() {returnone;

}publicV getTwo() {returntwo;

}public static voidmain(String[] args) {

Generic generic = new Generic<>(2,2.3);

Integer one=generic.getOne();

Double two=generic.getTwo();

System.out.println(one);

System.out.println(two);

}

}

另一中比较常见的是限定上界为一个接口,类型参数必须实现这个接口。在泛型方法中有一种场景就是限定的类型必须实现Comparable接口:

public static > T max(Listarr) {

T max= arr.get(0);for (int i = 1; i < arr.size(); i++) {if (arr.get(i).compareTo(max) > 0) {

max= arr.get(i);

}

}returnmax;

}

这个max方法是计算list集合中的最大值,所以需要在list集合中的元素实现Comparable接口。上面介绍的上界都是具体存在的类和接口,在java中允许也上界为一个类型参数。首先我们需要先定义一个容器类:

public class SimpleArrayList{private static final int DEFAULT_CAPACITY = 20;private intsize;privateObject[] element;publicSimpleArrayList() {this.element = newObject[DEFAULT_CAPACITY];

}private void ensureCapacity(intminCapacity) {int oldCapacity =element.length;if (oldCapacity >=minCapacity) {return;

}int newCapacity = oldCapacity * 2;if (newCapacity

newCapacity=minCapacity;

}

element=Arrays.copyOf(element, newCapacity);

}public voidadd(E e) {

ensureCapacity(size+ 1);

element[size++] =e;

}public E get(intindex) {return(E) element[index];

}public intsize() {returnsize;

}

}

这个容器类是使用数组来存放数据的,当存放的数据数量大于数组长度是就会进行扩容。假如现在我们需要在这个容器类中添加一个addAll的方法,我们可以这样来写:

public void addAll(SimpleArrayListc) {for (int i = 0; i < c.size; i++) {

add(c.get(i));

}

}

这样写看起来并没有什么错误,我们也可以把集合全部添加进去:

public static voidmain(String[] args) {

SimpleArrayList list = new SimpleArrayList<>();

SimpleArrayList list1 = new SimpleArrayList<>();

list1.add(1);

list1.add(2);

list1.add(3);

list.addAll(list1);

}

可是如果仔细观察会发现list和list1传递进来的参数类型都是Number类型的,如果我们把list1的改成这样:

public static voidmain(String[] args) {

SimpleArrayList list = new SimpleArrayList<>();

SimpleArrayList list1 = new SimpleArrayList<>();

list1.add(1);

list1.add(2);

list1.add(3);

list.addAll(list1);

}

那么addAll方法会在编译期间报错。这是因为addAll需要的参数类型是SimpleArray类型的不是SimpleArray类型,即使Integer是Number类型的子类也是不行的。可是我们需求是没有错的,Number的集合当然可以存放Integer,所以我们需要修改一下addAll方法。

public void addAll(SimpleArrayListc) {for (int i = 0; i < c.size; i++) {

add(c.get(i));

}

}

我们修改addAll方法,其中T是addAll的类型参数,E是SimpleArrayList的类型参数,T的上限是E,这样addAll方法就不会报错了。

在java泛型中还有一个不太好理解的知识点叫做通配符。在上面举得这个例子中如果addAll不使用通配符写难免有一些臃肿,使用通配符后方法就会变得简洁一点。

public void addAll(SimpleArrayList extends E>c) {for (int i = 0; i < c.size; i++) {

add(c.get(i));

}

}

其中?表示通配符 extends E>叫做有限定通配符,可以匹配E或者E的子类。和 extends E>有什么区别吗?用来定义类型参数,它声明了一个类型参数T; extends E>用来实例化类型参数,它用于实例化泛型变量的类型参数,只是这个实例化的类型是未知的。当使用通配符来实例化类型参数时会有一些限制,例如:

public static voidmain(String[] args) {

List> list = new ArrayList<>();

list.add("1");

}

上面的代码会报错,因为使用> 和使用 extends E>来实例化类型参数后集合只能读,不能写。这是因为java无法确保类型的安全性所以只能禁止这样操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值