Java 为什么可以';在一个有界通配符泛型中是否有多个接口?
我知道Java的泛型类型有各种违反直觉的属性。这里有一个我特别不明白的,我希望有人能给我解释一下。为类或接口指定类型参数时,可以将其绑定,以便它必须使用Java 为什么可以';在一个有界通配符泛型中是否有多个接口?,java,generics,language-design,bounded-wildcard,Java,Generics,Language Design,Bounded Wildcard,我知道Java的泛型类型有各种违反直觉的属性。这里有一个我特别不明白的,我希望有人能给我解释一下。为类或接口指定类型参数时,可以将其绑定,以便它必须使用公共类Foo实现多个接口。但是,如果您正在实例化一个实际的对象,这将不再有效列表好问题。我花了一段时间才弄明白 让我们来简化您的情况:您正在尝试执行相同的操作,就像您声明了一个扩展了两个接口的类,然后声明了一个将这两个接口作为类型的变量一样,如下所示: class MyClass implements Int1, Int2 { } In
公共类Foo
实现多个接口。但是,如果您正在实例化一个实际的对象,这将不再有效<代码>列表好问题。我花了一段时间才弄明白
让我们来简化您的情况:您正在尝试执行相同的操作,就像您声明了一个扩展了两个接口的类,然后声明了一个将这两个接口作为类型的变量一样,如下所示:
class MyClass implements Int1, Int2 { }
Int1 & Int2 variable = new MyClass()
当然,这是非法的。
这相当于您尝试对泛型所做的操作。
您试图做的是:
List<? extends A & B> foobar;
这在Java中是不合法的。这意味着,您将列表中的元素同时声明为两种类型,即使我们的大脑能够处理它,Java语言也不能
4.9交叉口类型
交叉点类型的形式为T1&…&Tn,n>0,其中Ti,1in是类型表达式。交叉口类型出现在捕获转换(§5.1.10)和类型推断(§15.12.2.7)过程中不可能将交叉点类型直接作为程序的一部分写入;没有语法支持此功能。交叉点类型的值是指所有类型Ti(1in)的值的对象
那么,为什么不支持这一点呢?我猜,你应该怎么处理这样的事情让我们假设这是可能的:
List<? extends A & B> list = ...
返回?没有语法捕获返回值
a&B
。在这样的列表中添加一些内容也是不可能的,所以基本上没有用。没问题。。。只需在方法签名中声明所需的类型
这包括:
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!
}
publicstaticvoidmain(字符串[]args)引发异常
{
AandBList foo=new AandBList();//这很好用!
foo.getList().add(新的AandB());
List有趣的是,接口java.lang.reflect.WildcardType
看起来既支持通配符arg的上界,也支持其下界;每个接口都可以包含多个边界
Type[] getUpperBounds();
Type[] getLowerBounds();
这远远超出了语言允许的范围。源代码中有一个隐藏的注释
// one or many? Up to language spec; currently only one, but this API
// allows for generalization.
<> P>界面的作者似乎认为这是一个偶然的限制。
你的问题的固定答案是,泛型已经太复杂了;增加复杂性可能是最后一根稻草
要允许通配符具有多个上限,必须扫描规范并确保整个系统仍然工作
我所知道的一个问题是类型推理。当前的推理规则根本无法处理交叉点类型。没有规则来减少约束a&B,因为它是值得的:如果有人想知道这一点,因为他们真的希望在实践中使用它,我已经通过定义一个包含unio的接口来解决它我正在使用的所有接口和类中的所有方法中的n个。例如,我尝试执行以下操作:
class A {}
interface B {}
List<? extends A & B> list;
class A{}
接口B{}
列表两点:第一,它看起来更像“扩展A,B”。第二,A和B可以不是接口,而是类(当然这可以由编译器检测)。不。字符&
是表示多个边界的标准方式。“类AandBList
”这就是语言的工作原理,尽管我同意使用
来匹配公共接口A扩展C,D
。并且,在泛型类型边界中,无论是接口还是类,都使用扩展
。我知道这会让人困惑,但这就是当前的方式。感谢链接!这就是我的理解非常有用。我想我会用它做的是A=list.get(0);
和B=list.get(0)
两者都是安全的。不过,我想我可以随时进行重构以获得一个通用的超级接口。>>>没有语法来捕获a&B的返回值。向这样的列表中添加一些内容也不可能,所以基本上是没有用的。如果你扩展
,你无论如何也不能放入该列表中。要获得,你可以简单地说a=list.get(0)
或B=list.get(0)
。我认为这不存在类型理论上的问题,这只是java的局限性。另一方面,我同意@opdecrkel。如果您有一个类型SomeClass
,它声明了一个返回List
的方法,然后对类型为SomeClass
的变量调用该方法,那么这种情况就已经发生了。对于JLS,请使用+1参考but-1进行猜测。假设A和B是接口,并且所有J、K、L都实现了A和B(在它们实现的其他接口中)。那么list
可以包含J、K和L的元素以及list。get(0)
可以返回它们。事实上,Java规范正确地指出,没有办法直接表达这个概念,但是J、K和L通过接口的多重继承间接地利用了它。-1正如波希米亚人指出的,语法稍有不同是可能的。没错,但同时作为两种类型,我们可以安全地将其视为一种或者另一个,在不同的时间独立。两者都是A=list.get(0);
和B=list.get(0);
将是有效的。“将需要使用”是错误的,你不是被迫这样做的,我看不到限制,这样做也是合法的:C类{public t foo(){};}
返回具有多个边界的变量。问题在于直接使用结果,而不是将其存储在变量中。例如,list.get(0)有哪些方法可用.*
?这是正确的,但它没有解释为什么类型参数的值不能不是中定义的引用类型,引用类型为defin
Type[] getUpperBounds();
Type[] getLowerBounds();
// one or many? Up to language spec; currently only one, but this API
// allows for generalization.
A<<C
or
A<<B
class A {}
interface B {}
List<? extends A & B> list;
class A {
<A methods>
}
interface B {
<B methods>
}
interface C {
<A methods>
<B methods>
}
List<C> list;