在 Java 的泛型类型中使用通配符

本文介绍Java泛型及通配符的基本概念,并详细解释如何使用通配符来实现方法参数类型的灵活性,包括无界通配符、上界通配符和下界通配符的应用。
在 Java 的泛型类型中使用通配符

Java 从版本5起开始引入泛型(generics)机制。我们知道,Java 的泛型类型如同 java.lang.String,java.io.File 一样,属于普通的 Java 类型。比方说,下面两个变量的类型就是互不相同的:

List<Object> listObj = new ArrayList<Object>();
List<String> listStr = new ArrayList<String>();

虽然 String 是 Object 的子类,但是 List<String> 和 List<Object> 之间并没有什么关系——List<String> 不是 List<Object> 的子类或者子类型。在下面的代码中,我们会看到将具有 List<Object> 类型的变量赋给期望 List<Object> 类型参数的方法的话,编译器在编译期将会报告一个编译错误。

import java.util.ArrayList;
import java.util.List;

public class GenericsTypeTest {
public static void testMtd(List<Object> l) {
}

public static void main(String[] args) {
List<String> testList = new ArrayList<String>;
// above line will cause a compile error
testMtd(testList);
}
}

如果我们希望 testMtd 能够接受任意泛型类型的参数,那么我们应该使用 ? 通配符来满足这个要求。List<?> 任意类型的对象的数组这么一个泛型的类型。我们可以把以上代码改成:

public static void testMtd(List<?> l) {
}

但是这种情况下,testMtd 的参数可以接受类型可能对于程序员设计的意图而言太广泛了一点。因为我们可能只是希望 testMtd 可以接受 AbstractList 及其子类的类型的变量,而不接受 AbstractSet 甚至 Random、Locale 等类型的变量。我们要对通配符有所限制。幸运的是,Java 5 的泛型机制已经考虑到了这一点,我们可以使用边界通配符(bounded wildcard)形式来满足这个要求。我们将 testMtd 再修改一下:

Public static void testMtd(List<? Extends AbstractList>) {
}

这样,List<AbstractList>、List<LinkedList> 等等类型的变量就可以传给 testMtd 方法,而储存其他类型元素的 List 的泛型类型变量传给 testMtd 方法将是非法的。除了上边界通配符(upper bounded wildcard)以外,我们还可以使用下边界通配符(lower bounded wildcard),例如 List<? super AbstractList>。

最后总结一下使用通配符的泛型类型的三种形式:

GenericType<?>
GenericType<? extends upperBoundType>
GenericType<? super lowerBoundType>
### 通配符方法中的使用 Java 中的通配符 `?` 被用来表示未知类型,从而增强代码的灵活性和通用性。在方法中,通配符可以用于处理不确定的类型参数,使得方法能够适应多种类型的输入。通配符使用通常包括无界通配符、上界通配符和下界通配符,它们分别适用于不同的场景。 #### 无界通配符(Unbounded Wildcards) 无界通配符使用 `<?>` 表示,表示可以接受任何类型参数。它适用于不需要访问集合元素内容的场景。例如,当只需要遍历集合而不需要对其中的元素进行操作时,可以使用无界通配符。 ```java public static void printCollection(Collection<?> collection) { for (Object obj : collection) { System.out.println(obj); } } ``` 此方法可以接受任何类型的 `Collection`,例如 `Collection<String>` 或 `Collection<Integer>`,但不能向其中添加任何元素(除了 `null`)[^3]。 #### 上界通配符(Upper Bounded Wildcards) 上界通配符使用 `<? extends T>` 表示,表示接受的类型必须是 `T` 类型或其子类型。这种方式适用于需要读取集合元素并保证其类型的场景。例如,当需要处理一个包含 `Number` 或其子类(如 `Integer`、`Double`)的集合时,可以使用上界通配符。 ```java public static double sum(Collection<? extends Number> numbers) { double sum = 0.0; for (Number number : numbers) { sum += number.doubleValue(); } return sum; } ``` 该方法可以接受 `Collection<Integer>` 或 `Collection<Double>` 等作为参数,并安全地读取其中的数值[^5]。 #### 下界通配符(Lower Bounded Wildcards) 下界通配符使用 `<? super T>` 表示,表示接受的类型必须是 `T` 类型或其父类型。这种方式适用于需要向集合中写入数据的场景。例如,当需要向一个 `List` 中添加 `Integer` 类型的数据时,可以使用下界通配符。 ```java public static void addIntegers(List<? super Integer> list) { list.add(1); list.add(2); } ``` 该方法可以接受 `List<Integer>`、`List<Number>` 或 `List<Object>` 等作为参数,并向其中添加 `Integer` 类型的值[^5]。 #### 通配符的捕获 通配符的一个限制是不能直接向使用通配符的集合中添加元素(除了 `null`)。然而,可以通过方法和类型推断来“捕获”通配符的实际类型,从而实现更灵活的操作。例如,可以定义一个方法来复制集合中的元素: ```java private static <T> void copy(Collection<T> dest, Collection<T> src) { for (T t : src) { dest.add(t); } } public static void wildcardCopy(Collection<?> src, Collection<? super Object> dest) { copy((Collection<Object>) src, dest); } ``` 在此示例中,`wildcardCopy` 方法使用通配符来接受任意类型的集合,而 `copy` 方法则通过类型参数 `T` 来捕获实际类型,从而实现集合的复制[^1]。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值