Adr*_*scu 69 java generics language-design bounded-wildcard
我知道Java的泛型类型存在各种反直觉属性.这是我不理解的一个,我希望有人可以向我解释.为类或接口指定类型参数时,可以绑定它以使其必须实现多个接口public class Foo<T extends InterfaceA & InterfaceB>
.但是,如果您要实例化实际对象,则此功能不再起作用.List<? extends InterfaceA>
很好,但List<? extends InterfaceA & InterfaceB>
无法编译.请考虑以下完整代码段:
import java.util.List;
public class Test {
static interface A {
public int getSomething();
}
static interface B {
public int getSomethingElse();
}
static class AandB implements A, B {
public int getSomething() { return 1; }
public int getSomethingElse() { return 2; }
}
// Notice the multiple bounds here. This works.
static class AandBList<T extends A & B> {
List<T> list;
public List<T> getList() { return list; }
}
public static void main(String [] args) {
AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
foo.getList().add(new AandB());
List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
// This last one fails to compile!
List<? extends A & B> foobar = new LinkedList<AandB>();
}
}
Run Code Online (Sandbox Code Playgroud)
似乎bar
应该明确定义语义- 我不能通过允许两种类型的交集而不仅仅是一种来考虑类型安全性的任何损失.我确定有一个解释.有谁知道它是什么?
irr*_*ble 36
有趣的是,界面java.lang.reflect.WildcardType
看起来像支持通配符arg的上限和下限; 每个都可以包含多个边界
Type[] getUpperBounds();
Type[] getLowerBounds();
Run Code Online (Sandbox Code Playgroud)
这超出了语言允许的范围.源代码中有一个隐藏的注释
// one or many? Up to language spec; currently only one, but this API
// allows for generalization.
Run Code Online (Sandbox Code Playgroud)
界面的作者似乎认为这是一个偶然的限制.
你的问题的罐头答案是,仿制药已经太复杂了; 增加更多的复杂性可能是最后一根稻草.
要允许通配符具有多个上限,必须扫描规范并确保整个系统仍然有效.
我知道的一个问题是类型推断.当前的推理规则根本无法处理拦截类型.减少约束没有规则A&B << C
.如果我们减少它
A<<C
or
A<<B
Run Code Online (Sandbox Code Playgroud)
任何当前的推理引擎都必须经过大修以允许这样的分叉.但真正严重的问题是,这允许多种解决方案,但没有理由更喜欢一个而不是另一个.
但是,推理对于打字安全并不重要; 在这种情况下,我们可以简单地拒绝推断,并要求程序员明确填写类型参数.因此,推理的难度并不是反对拦截类型的有力论据.
emb*_*oss 25
从Java语言规范:
4.9交点类型交集类型采用T1&...&Tn形式,n> 0,其中Ti,1in是类型表达式.交叉类型出现在捕获转换(第5.1.10节)和类型推断(第15.12.2.7节)的过程中.不能直接将交集类型写为程序的一部分; 没有语法支持这个.交集类型的值是那些是所有类型Ti的值的对象,对于1in.
那么为什么不支持这个呢?我的猜测是,你应该怎么做这样的事情? - 让我们假设它是可能的:
List<? extends A & B> list = ...
Run Code Online (Sandbox Code Playgroud)
那该怎么办呢
list.get(0);
Run Code Online (Sandbox Code Playgroud)
返回?没有语法来捕获返回值A & B
.在这样的列表中添加内容也是不可能的,所以它基本上没用.
Boh*_*ian 11
没问题......只需在方法签名中声明您需要的类型.
这编译:
public static <T extends A & B> void main(String[] args) throws Exception
{
AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
foo.getList().add(new AandB());
List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
List<T> foobar = new LinkedList<T>(); // This compiles!
}
Run Code Online (Sandbox Code Playgroud)