【问题标题】:Java Generics With a Class & an Interface - Together具有类和接口的 Java 泛型 - 一起使用
【发布时间】:2021-09-21 01:05:06
【问题描述】:

我想要一个 Class 对象,但我想强制它所代表的任何类扩展类 A 并实现接口 B。

我能做到:

Class<? extends ClassA>

或者:

Class<? extends InterfaceB>

但我不能两者都做。有没有办法做到这一点?

【问题讨论】:

    标签: java class generics bounded-wildcard


    【解决方案1】:

    其实,你可以做你想做的事。如果你想提供多个接口或一个类加接口,你必须让你的通配符看起来像这样:

    <T extends ClassA & InterfaceB>
    

    请参阅 sun.com 上的 Generics Tutorial,特别是页面底部的 Bounded Type Parameters 部分。如果您愿意,您实际上可以列出多个接口,对您需要的每个接口使用&amp; InterfaceName

    这可能会变得任意复杂。为了演示,请参阅Collections#max 的 JavaDoc 声明,它(包装成两行)是:

    public static <T extends Object & Comparable<? super T>> T
                                               max(Collection<? extends T> coll)
    

    为什么这么复杂?正如 Java 泛型常见问题解答中所说:To preserve binary compatibility

    看起来这不适用于变量声明,但在将泛型边界放在类上时它确实有效。因此,要做你想做的事,你可能需要跳过几个圈。但你可以做到。你可以做这样的事情,在你的类上设置一个通用的边界,然后:

    class classB { }
    interface interfaceC { }
    
    public class MyClass<T extends classB & interfaceC> {
        Class<T> variable;
    }
    

    获取具有您想要的限制的variable。有关更多信息和示例,请查看Generics in Java 5.0 的第 3 页。注意,在&lt;T extends B &amp; C&gt; 中,类名必须在前,接口在后。当然,您只能列出一个类。

    【讨论】:

    • 这很有帮助。值得一提的是,类必须在前,不能说''。
    • 如果 T 扩展类或实现接口,您如何做同样的事情?
    • @RagunathJawahar:你不能对此太过开放。你必须有一些界限,其中之一是提前知道你将在哪里拥有接口和你将在哪里拥有类,以及你将如何使用继承。您几乎必须知道类型参数是类还是接口。
    • 你的答案的第一行说“让你的通配符看起来像这样”。该表达式中没有?,所以它真的是“通配符”吗?我问是因为当类型参数确实是通配符时,我无法让整个“同时扩展两件事”的概念起作用。
    • 是的,它不是真正的通配符,你不能用通配符做 OP 要求的事情。您可以有效地执行 OP 想要的操作,而无需使用通配符。
    【解决方案2】:

    您不能使用“匿名”类型参数(即使用? 的通配符)来执行此操作,但您可以使用“命名”类型参数执行此操作。只需在方法或类级别声明类型参数即可。

    import java.util.List;
    interface A{}
    interface B{}
    public class Test<E extends B & A, T extends List<E>> {
        T t;
    }
    

    【讨论】:

    • 为什么不允许使用通配符?即我不明白为什么这不应该是有效的:ArrayList 列表;然后,如果您从列表中拉出一个元素,您可以将其分配给 ClassA 类型或 InterfaceB 类型的变量
    • 用变量替换通配符是一项很棒的技术!但它并不总是有效。例如,Java 不允许在注解值类型中使用名称类型变量,但允许使用通配符。
    【解决方案3】:

    这是你在 Kotlin 中的做法

    fun <T> myMethod(item: T) where T : ClassA, T : InterfaceB {
        //your code here
    }
    

    【讨论】:

    • 如果你投反对票,你能补充解释吗?
    • 我投了赞成票,但如果这还不是负面的话,我可能会投反对票。尽管大肆宣传,但我还没有准备好放弃 Java 转而使用 Kotlin。甚至对于 Scala,我更喜欢 Kotlin。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 2021-10-27
    • 2021-01-25
    • 2019-12-06
    • 2020-11-28
    相关资源
    最近更新 更多