为什么使用通配符捕获帮助程序方法?

2022-09-03 14:25:18

参考:通配符捕获帮助程序方法

它说要创建一个帮助器方法来捕获通配符。

public void foo(List<?> i) {
    fooHelper(i);
}        
private <T> void fooHelper(List<T> l) {
    l.set(0, l.get(0));
}

仅在下面单独使用此函数不会产生任何编译错误,并且似乎以相同的方式工作。我不明白的是:你为什么不直接使用这个,避免使用助手?

public <T> void foo(List<T> l) {
    l.set(0, l.get(0));
}

我以为这个问题可以归结为:通配符和泛型之间有什么区别?所以,我谈到了这个:通配符和泛型之间的区别。它说要使用类型参数:

1)如果你想在不同类型的方法参数上强制实施一些关系,你不能用通配符来做到这一点,你必须使用类型参数。

但是,这不正是带有辅助函数的通配符实际上正在做的事情吗?它是否在不同类型的方法参数上强制执行关系,并设置和获取未知值?

我的问题是:如果你必须定义一些需要在不同类型的方法参数上建立关系的东西,那么为什么首先使用通配符,然后使用它的帮助器函数呢?

这似乎是一种合并通配符的黑客方式。


答案 1

在这种特殊情况下,这是因为 List.set(int, E) 方法要求类型与列表中的类型相同。

如果您没有帮助器方法,编译器不知道 是否相同,并且返回自,因此您会收到编译器错误:?List<?>get(int)

The method set(int, capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (int, capture#2-of ?)

使用帮助器方法,您告诉编译器,类型是相同的,我只是不知道类型是什么。

那么为什么有非帮助器方法呢?

泛型直到Java 5才被引入,所以有很多代码早于泛型。Java 5之前的版本现在是,因此,如果您尝试在通用感知编译器中编译旧代码,则如果无法更改方法签名,则必须添加这些帮助器方法。ListList<?>


答案 2

我同意:删除帮助器方法并键入公共API。没有理由不这样做,而且有充分的理由这样做。

只是为了总结通配符版本对帮助者的需求:尽管这对我们人类来说很明显,但编译器并不知道从中返回的未知类型与列表本身的未知类型相同。即,它不考虑调用的参数来自与目标相同的列表对象,因此它必须是安全的操作。它只注意到从返回的类型是未知的,目标列表的类型是未知的,并且两个未知数不能保证是同一类型。l.get(0)set()get()


推荐