Java学习笔记之泛型(三) 泛型的限制与通配符

在前两篇文章中介绍了泛型的基本用法和泛型的继承问题,本文将介绍泛型的高级用法:泛型的限制和通配符。

一、泛型的限制

我们可以使用任意的类型来指定一个泛型,这样是存在一定的弊端的。Java也提供了一种语法来限制泛型的指定类:

<T extends ClassOrInterface>

这里面ClassOrInterface可以是类或者是接口,有了这个限制之后,泛型T必须是ClassOrInterface的子类或者实现类,否则编译报错。举例如下:
在这里插入图片描述
例子里面我们将泛型限制为List的子类,因为HashSet是Set的子类,所以代码在第10行报错了。上面的例子是一个泛型类的例子,接下来再举一个泛型方法的例子:
在这里插入图片描述
可以看到在泛型方法show中将T限制为List或其子类,而String类型不是它的子类,所以第15行报错。

使用泛型限制之后除了能限制泛型的指定类之外,还有一个作用。我们考虑一个问题,那在泛型类A内部,利用泛型定义的变量T t能调用哪些方法呢?来看一看:

在这里插入图片描述
可以看到,T的对象t只能调用Object的方法。因为编译器根本不知道T具体是什么类型,只有在运行时,用户给什么类型才知道是什么类型。编译器唯一能确定的是,无论什么类型,都是派生自Object的,所以T肯定是Object的子类,所以T是可以调用Object的方法的。

那么对泛型做了限制之后,是否就能够调用一些特定的方法呢?

在这里插入图片描述
可以看到,限制泛型T为List子类之后,变量t就可以调用List里面提供的方法了。

二、通配符

在泛型机制中提供了一个类型通配符,那么为什么要引入通配符呢?这里举一个例子:

public class Test {
	public static void main(String args[]) {
		ArrayList<String> al1 = new ArrayList<>();
		al1.add("haha");
		al1.add("hehe");
				
		ArrayList<Integer> al2 = new ArrayList<>();
		al2.add(1);
		al2.add(2);
		
		new Test().printList(al1);
		new Test().printList(al2);
	}
	
	public void printList(这里面些什么参数呢?) {
		//打印的逻辑
	}

}

这个例子中,我们在主方法里面创建了两个ArrayList并给它们添加了一些元素,现在我想通过printList方法遍历打印容器中的东西,那么方法的参数写什么呢?是ArrayList< String >还是ArrayList< Integer >呢?这里因为我们不知道调用者想遍历什么类型的ArrayList,所以ArrayList中的泛型是未知的,这种情况就可以使用通配符?了。代码如下:

public void printList(List<?> list) {
	Iterator<?> it = list.iterator();
	while(it.hasNext()) {
		System.out.println(it.next());
	}
}

由这个例子我们知道了,当泛型类型不确定可以使用通配符。

同样的,对于通配符也可以加上限定,有3种情况:

1、无边界通配符:

A<?> a;  

2、上限通配符:

A<? extends ClassOrInterface> a; //泛型必须是ClassOrInterface或它的子类/实现类

3、下限通配符:

A<? extends ClassOrInterface> a; //泛型必须是ClassOrInterface或它的父类

值得注意的是,通配符只能用于填充泛型变量T(也就是在声明对象的时候使用),在定义泛型时使用会报错:

在这里插入图片描述
看下面这个例子:

在这里插入图片描述
因为HashSet不是List子类所以报错,ArrayList不是List父类所以报错。

猜你喜欢

转载自blog.csdn.net/weixin_44965650/article/details/106958544