【问题标题】:Overriding lower bounded arguments覆盖下界参数
【发布时间】:2018-03-01 17:02:23
【问题描述】:

我想知道为什么 java 不允许覆盖下界泛型参数。

public interface NumberConsumer {
    public void accept(Consumer<? super Number> consumer);
}

public interface IntegerConsumer extends NumberConsumer {
    @Override
    public void accept(Consumer<? super Integer> consumer);
}

在上面的示例中,重写方法 accept 是完全安全的,因为 NumberConsumer 可以接受数字、可序列化和对象的消费者,而 IntegerConsumer 也可以接受所有这些和整数。

这也是不允许的,尽管它也是完全安全的。

public interface IntegerPrinter {
    public void print(List<? extends Integer> list);
}

public interface NumberPrinter extends IntegerPrinter {
    @Override
    public void print(List<? extends Number> list);
}

这里 NumberPrinter 可以毫无问题地使用List&lt;? extends Integer&gt;

最后,一些类似的情况(或相反的情况)被允许在返回中。

public interface NumberListProducer {
    java.util.List<? extends Number> next();
}

public interface IntegerListProducer extends NumberListProducer {
    @Override
    java.util.List<? extends Integer> next();
}

【问题讨论】:

    标签: java generics overriding


    【解决方案1】:

    这不是泛型问题,而是 java 如何处理其overriding 特性。

    覆盖方法与它覆盖的方法具有相同的名称、参数数量和类型以及返回类型。覆盖方法还可以返回被覆盖方法返回的类型的子类型。此子类型称为协变返回类型。

    因此,仅在返回类型中才允许在覆盖方法中继承类型。类型的精确匹配应该发生在方法参数中。

    例如,以下情况抛出错误。

    1. interface PaterntInterface {
          public void accept(Integer consumer);
      }
      
      interface ChildInterface extends NumberConsumer {
          @Override
          public void accept(Number consumer);
      }
      
    2. interface PaterntInterface {
          public void accept(Number consumer);
      }
      
      interface ChildInterface extends NumberConsumer {
          @Override
          public void accept(Integer consumer);
      }
      

      以下情况编译正确。

    3. interface PaterntInterface {
          public void accept(Integer consumer);
      }
      
      interface ChildInterface extends NumberConsumer {
          @Override
          public void accept(Integer consumer);
      }
      
    4. interface PaterntInterface {
          public void accept(Number consumer);
      }
      
      interface ChildInterface extends NumberConsumer {
          @Override
          public void accept(Number consumer);
      }
      

    你的论点是你的第一种情况,

    public interface NumberConsumer {
        public void accept(Consumer<? super Number> consumer);
    }
    
    public interface IntegerConsumer extends NumberConsumer {
        @Override
        public void accept(Consumer<? super Integer> consumer);
    }
    

    应该没问题,因为Consumer&lt;? super Integer&gt;Consumer&lt;? super Number&gt; 的超类无效,因为重写需要方法参数类型的精确匹配。对于您的第二种情况也是如此。 第三种情况编译是因为java.util.List&lt;? extends Integer&gt;java.util.List&lt;? extends Number&gt; 的子类型,并且在方法覆盖中允许继承返回类型

    【讨论】:

    • 你说得对,但最好能解释一下为什么这些是限制
    • 我同意@Amit 的观点,为什么这么多年Java 还没有改进呢?对编译器来说太难了吗?很明显,子类不能接受更具体的参数,因为那样它就不能处理超类的参数,但是为什么孩子不能接受不太具体的参数是完全安全的。
    • 本例中更具体的内容是 Number 及以上(Number, Serializable, Object,即 super Number>)和不太具体的(Integer, Number, Serializable 和 Object,即 )
    • @JoseDaSilva - 这有充分的理由(可能是官方的,但也有简单的“逻辑”原因)。我只是在暗示没有推理的答案是不完整的。
    • @Amir - 好的,但是这些原因是什么,哪一个是官方的,更容易根本不允许覆盖参数?我没有看到另一个不应该被允许的逻辑原因(除了它可能从未考虑过,也不会,或者这可能太难了,我个人对此表示怀疑),IntegerConsumer 可以完全像 NumberConsumer 一样对待。
    猜你喜欢
    • 2013-01-19
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 2015-06-05
    • 2016-01-03
    • 2020-11-03
    • 2012-05-20
    相关资源
    最近更新 更多