【问题标题】:Java: Help me understand: How to use interface methods on a bounded wildcard field?Java:帮助我理解:如何在有界通配符字段上使用接口方法?
【发布时间】:2013-01-13 01:11:16
【问题描述】:

如果我不能(似乎)使用任何(通用类型),我无法理解为什么我可以使用这样的有界通配符。

如果我在一个类中有一个通配符字段,我就不能使用任何带有已实现接口的泛型参数的方法(除非我提供null 作为参数)。

class SomeClass {}

class DerivedClass extends SomeClass {}

interface IInterf<T extends SomeClass> {
    T returnsT();
    void paramT(T parm);
    T paramAndReturnT(T parm);
    int nonGenericMethod(int x);
}

class Impl {
    protected IInterf<?> field; //this is bound to <extends SomeClass>
                                //- it's implied by the definition 
                                //  of IInterf which is bound
                                // but what's the point?

    public Impl(IInterf<? extends SomeClass> var){
        field = var;
    }
    public void doSmth(){

        SomeClass sc = field.returnsT();  //works

        field.paramT(new SomeClass());
          //error: method paramT in interface IInterf<T> cannot be applied to given types;
          //required: CAP#1
          //found: SomeClass
          //reason: actual argument SomeClass cannot be converted to CAP#1 by method invocation conversion
          //where T is a type-variable:
          //  T extends SomeClass declared in interface IInterf
          //where CAP#1 is a fresh type-variable:
          //  CAP#1 extends SomeClass from capture of ? 

         field.paramT(null); //works

        SomeClass sc2 = field.paramAndReturnT(new DerivedClass());
          //error: method paramAndReturnT in interface IInterf<T> cannot be applied to given types;
          // SomeClass sc2 = field.paramAndReturnT(new DerivedClass());           //required: CAP#1
          //found: DerivedClass
          //reason: actual argument DerivedClass cannot be converted to CAP#1 by method invocation conversion
          //where T is a type-variable:
          //  T extends SomeClass declared in interface IInterf
          //where CAP#1 is a fresh type-variable:
          //  CAP#1 extends SomeClass from capture of ?            
          //
        int x = field.nonGenericMethod(5);  //obviously works.
    }
}

FWIW,我无法说服 C# 编译器接受类似的东西。

我错过了什么吗?

【问题讨论】:

    标签: java generics wildcard bounded-wildcard


    【解决方案1】:

    当您将field 声明为

    protected IInterf<?> field;
    

    ? 代表扩展SomeClass 的未知类。认为它不是一个通配符,而是一个派生 SomeClass 但匿名的特定类。

    如果你现在尝试调用

    field.paramT(new SomeClass());
    

    这失败了,因为 SomeClass 实例与 ? 所代表的内容不兼容,即扩展 SomeClass 的匿名类。

    使用null没有问题,这兼容任何类。

    同样的情况发生在

    SomeClass sc2 = field.paramAndReturnT(new DerivedClass());
    

    【讨论】:

    • 您的解释并不完全正确:当使用protected IInterf&lt;?&gt; field; 时,即使field.paramAndReturnT(new DerivedClass()); 将无法编译,即使DerivedClass 扩展SomeClass
    • @praseodym 我在哪里说它会编译? ? 代表扩展SomeClass 的未知类。这个未知的类与DerivedClass 无关,只是两者恰好都有SomeClass 作为超类。
    • 你没有,但我从“? 代表什么,即扩展SomeClass 的类”中推断出这一点。因为DerivedClass 确实扩展了SomeClass - 它比这更复杂(见我的回答)。
    • @praseodym:亨利是正确的。他的解释非常清楚。 ? 代表 SomeClass 的某个未知子类型,即它是某个子类,您不知道也不知道它是什么。即编译器可以将其替换为SomeClass 的任何子类(例如DerivedClass 甚至SomeBogusSubclassIMadeUp)并且它会起作用。 DerivedClass 无法传递,因为它不能分配给 SomeBogusSubclassIMadeUp
    【解决方案2】:

    你是对的,你不能使用这些方法。通常,您不需要这些方法(例如,您将 &lt;? extends T&gt; 添加到集合 &lt;T&gt;。如果您不需要更多信息,则使用它们是有意义的。如果您需要调用这些方法,您不能使用通配符。相反,你可以使用&lt;T extends SomeClass&gt;

    【讨论】:

      【解决方案3】:

      您正在尝试在不需要的地方使用泛型/通配符。相反,以下任一方法都可以:

      1) 定义接口,使其接受任何类,并在使用接口时限制类型:

      interface IInterf<T> {}
      protected IInterf<SomeClass> field;
      

      2) 定义接口,使其接受扩展SomeClass的类,并在不指定额外类型信息的情况下使用接口:

      interface IInterf<T extends SomeClass> {}
      protected IInterf field;
      

      至于为什么通配符不起作用:? extends SomeClass 表示 SomeClassunknown 子类型。由于我们不知道类型是什么,所以我们不知道它是否是SomeClass(或第二个方法调用中的DerivedClass)的超类型;它可能是也可能不是这样的超类型,因此传递SomeClass(或DerivedClass)是不安全的。 (来自Java Wildcards documentation

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多