我想做以下事情:
public class ImmutableList<T> {
public <U super T> ImmutableList<U> add(U element) { ... }
}
也就是说,给定一个 的不可变列表T
,您可以将任何添加U
到列表中以生成一个 的不可变列表U
,其约束U
必须是 的超类型T
。例如
- 我可以将一只猴子添加到猴子列表中,从而产生一个新的猴子列表;
- 我可以将人类添加到猴子列表中,从而生成新的原始人列表(大概是猴子和人类的最小上限);
- 我可以将一块岩石添加到原始人列表中,从而生成一个新列表
Object
(假设岩石和原始人没有其他共同祖先)。
这在理论上听起来不错,但根据 JLS,下限U
是不合法的。我可以改写:
public class ImmutableList<T> {
public ImmutableList<T> add(T element) { ... }
public static <U> ImmutableList<U> add(ImmutableList<? extends U> list, U element) { ... }
}
U
以这种方式,编译器将正确推断列表的元素类型与我们要添加的元素类型之间的最小上限。这是合法的。它也很烂。比较:
// if 'U super T' were legal
list.add(monkey).add(human).add(rock);
// assuming 'import static ImmutableList.add'
add(add(add(list, monkey), human), rock);
我是函数式编程的忠实粉丝,但我不希望我的 Java 代码看起来像 Lisp 方言。所以我有三个问题:
怎么回事?为什么
<U super T>
绑定不合法?这个问题实际上已经在这里被问过(“为什么 Java 类型参数不能有下限?”)但我认为这个问题的措辞有点混乱,那里的答案归结为“它不够有用”,我真的不买。JLS 第 4.5.1 节指出:“与在方法签名中声明的普通类型变量不同,使用通配符时不需要类型推断。因此,允许在通配符上声明下限。” 鉴于
static
上面的替代方法签名,编译器显然能够推断出它需要的最小上限,所以这个论点似乎被打破了。有人可以说不是吗?最重要的是:有人能想出一个合法的替代我的方法签名的下限吗?简而言之,目标是让调用代码看起来像 Java (
list.add(monkey)
) 而不是 Lisp (add(list, monkey)
)。