为什么使用通配符捕获助手方法?
参考: 通配符捕获助手方法
它说要创建一个辅助方法来捕获通配符。
public void foo(List i) { fooHelper(i); } private void fooHelper(List l) { l.set(0, l.get(0)); }
仅在下面单独使用此函数不会产生任何编译错误,并且似乎以相同的方式工作。 我不明白的是:你为什么不使用这个并避免使用助手?
public void foo(List l) { l.set(0, l.get(0)); }
我认为这个问题可以归结为:通配符和generics之间有什么区别? 所以,我去了这个: 通配符和generics之间的区别 。 它说要使用类型参数:
1)如果要对不同类型的方法参数强制实施某些关系,则不能使用通配符,必须使用类型参数。
但是,具有辅助函数的通配符实际上并不是这样吗? 是不是通过设置和获取未知值来强制执行不同类型的方法参数的关系?
我的问题是:如果你必须定义需要在不同类型的方法args上建立关系的东西,那么为什么首先使用通配符然后使用辅助函数呢?
这似乎是一种结合通配符的hacky方式。
在这种特殊情况下,因为List.set(int,E)方法要求类型与列表中的类型相同。
如果你没有helper方法,编译器不知道是否?
对于List>
和get(int)
的返回是一样的,所以你得到一个编译器错误:
The method set(int, capture#1-of ?) in the type List is not applicable for the arguments (int, capture#2-of ?)
使用helper方法,你告诉编译器,类型是一样的,我只是不知道类型是什么。
那么为什么要使用非辅助方法呢?
在Java 5之前没有引入generics,所以有许多代码早于generics。 Java 5之前的List
现在是List>
因此如果您尝试在通用感知编译器中编译旧代码,则必须添加这些辅助方法,如果您无法更改方法签名。
你是对的,我们不必使用通配符版本。
归结为哪个API看起来/感觉“更好”,这是主观的
void foo(List> i) void foo(List i)
我会说第一个版本更好。
如果有界限
void foo(List extends Number> i) void foo(List i)
第一版看起来更紧凑; 类型信息都在一个地方。
在这个时间点,通配符版本是惯用的方式,它对程序员来说更熟悉。
JDK方法定义中有很多通配符,特别是在java8引入lambda / Stream之后。 不可否认,它们非常难看,因为我们没有变化类型。 但是想想如果我们扩展所有通配符来输入vars会有多么丑陋。
我同意:删除帮助方法并键入公共API。 没有理由不和每一个理由。
只是总结一下使用通配符版本的帮助程序的需求:虽然我们作为人类很明显,但编译器不知道从l.get(0)
返回的未知类型与列表本身的未知类型相同 。 即它并不考虑set()
调用的参数来自与目标相同的列表对象,因此它必须是安全的操作。 它只注意到从get()
返回的类型是未知的,并且目标列表的类型是未知的,并且两个未知数不能保证是相同的类型。