Java Generics Wildcarding With Multiple Classes
我想要一个类对象,但是我想要强制它所代表的任何类来扩展类A和实现接口B。
我能做到:
或:
1
| Class<? extends InterfaceB> |
号
但我不能两者兼得。有办法吗?
实际上,你可以做你想做的。如果要提供多个接口或类加接口,则必须使通配符看起来像这样:
1
| <T extends ClassA & InterfaceB> |
请参阅sun.com上的generics教程,特别是页面底部的绑定类型参数部分。如果您愿意的话,您实际上可以列出多个接口,为您需要的每个接口使用& InterfaceName。
这会变得任意复杂。要演示,请参见Collections#max的javadoc声明,它(包装在两行中)是:
1 2
| public static <T extends Object & Comparable <? super T >> T
max (Collection <? extends T > coll ) |
号
为什么这么复杂?正如Java泛型常见问题解答:保存二进制兼容性。
看起来这对变量声明不起作用,但在类上放置泛型边界时,它起作用。因此,要想做你想做的事,你可能需要跳过几个圈。但你可以做到。您可以这样做,在类上放置一个通用边界,然后:
1 2 3 4 5 6
| class classB { }
interface interfaceC { }
public class MyClass<T extends classB & interfaceC> {
Class<T> variable;
} |
得到有你想要的限制的variable。有关更多信息和示例,请查看Java 5中泛型的第3页。注意,在中,类名必须在前面,接口在后面。当然,你只能列出一个类。
- 但是为什么我要在返回对象时把它投射到t上呢?
- @在我回答之前,你需要提供更多的信息。在什么情况下你需要演员?
- 这很有帮助。值得一提的是,类必须排在第一位,您不能说""。
- 也可以用逗号分隔,但只能用类分隔。
- 对于T,如何做同样的事情?应该扩展一个类或者实现一个接口?
- @Ragunathjawahar:你不能对此过于开放。你必须有一些边界,其中之一就是提前知道你将在哪里有接口,在哪里有类,以及你将如何使用继承。对于类型参数,您几乎必须知道它是类还是接口。
- @埃迪,你说得对。我知道了。它对于不同的用例是不同的。我最终用一种通用方法解决了我的问题。基类使用超级类指定边界。其中一个泛型方法通过扩展基类和接口缩小了范围。
- T extends Object部分的用途是什么?
- @中卓:在这种情况下,可能会有几个班,为什么他们会被昏迷分开?
- @njzk2:检查我在回答中对"保持二进制兼容性"的链接。它解释了为什么"T扩展对象"部分在那里。
- @埃迪:谢谢,我现在明白了。
- 回答的第一行是"让通配符看起来像这样",表达式中没有?,所以它真的是一个"通配符"?我这样问是因为当类型参数实际上是一个通配符时,我不能让整个"一次扩展两件事"概念起作用。
- 是的,它不是一个真正的通配符,你不能用一个通配符来做OP要求的事情。你可以做什么操作,有效地,只是不使用通配符。
- 很有趣,但您不能(表面上)做的是,因为1)类型参数必须在"&;"中位于最后,2)即使在该形式中,它也会生成"意外类型"。
不能使用"匿名"类型参数(即使用?的通配符),但可以使用"命名"类型参数。只需在方法或类级别声明类型参数。
1 2 3 4 5 6
| import java.util.List;
interface A{}
interface B{}
public class Test<E extends B & A, T extends List<E>> {
T t;
} |
。
- 为什么不允许使用通配符?也就是说,我不明白为什么这不应该是有效的:arraylist<?扩展ClassA&InterfaceB>List;然后,如果从列表中拉出一个元素,则可以将其分配给ClassA或InterfaceB类型的变量。
- 用变量替换通配符是一种很好的技术!但并不总是有效。例如,Java不允许注释值类型中的名称类型变量,但它允许通配符。