【问题标题】:Extending the contained type when implementing an Interface实现接口时扩展包含的类型
【发布时间】:2013-12-23 23:03:11
【问题描述】:

我创建了两个 Java 接口,Tree<T>BinarySearchTree<T extends Comparable<T>>,其中第二个接口扩展了第一个接口。我有一个BinarySearchTree 的实现,称为LinkedBinarySearchTree。以下代码在编译时显然会报错:

Tree<Object> a = new LinkedBinarySearchTree<Object>();

因为LinkedBinarySearchTree 实现的接口已将T 指定为Comparable 类型,而Objects 不是Comparable。我完全理解这一点,它不会对我的实现构成问题。

我希望了解的是,这种方法在实践中是否存在危险。我无法想象从TreeBinarySearchTree 的数据类型“缩小”会给我一个运行时错误(ClassCastException,也许?)但我希望与更多有知识的人确认这一点。本质上,在扩展接口时“缩小”接口持有的类型是否被认为是不好的做法,如果是,为什么?

【问题讨论】:

  • 不,这不是一个坏习惯。您可以通过不缩小类型并要求 Comparator 作为参数来使您的 BST 更通用,就像 TreeSet 一样。

标签: java inheritance interface


【解决方案1】:

事实上恰恰相反——这实际上是一种很好的做法。

请记住,使用泛型是一种通过在编译时捕获尽可能多的错误来避免编码错误的技术。通过加强BinarSearchTree 界面的特殊性,您实际上使人们更难误用它。不仅如此,他们的错误也会在编译时被发现。

【讨论】:

    【解决方案2】:

    这似乎一点也不坏。是否获得ClassCastException 取决于您尝试做什么,而不是实施方法。

    “缩小范围”的一个常见情况是当一个人想要专门化某些实现的类型,从一个共同的基础派生。例如,要实现一些计算器,每次都有不同的返回类型:

    public interface Calculator<T> {
        public Number calculate(T... arguments);
    }
    
    public interface NumberCalculator<T extends Number> extends Calculator<T> {
        @Override
        public T calculate(T... arguments);
    }
    
    public interface IntegerNumberCalculator extends NumberCalculator<Integer> {
        @Override
        public Integer calculate(Integer... arguments);
    }
    
    public interface FloatNumberCalculator extends NumberCalculator<Float> {
        @Override
        public Float calculate(Float... arguments);
    }
    

    上面的参数可以指定为与&lt;T&gt;不同的东西,而返回类型可以继续为每个子类设置为&lt;T&gt;,从而与必须返回Number相比提供更好的类型一致性一直反对。

    【讨论】:

      猜你喜欢
      • 2020-11-14
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 2020-03-09
      • 1970-01-01
      相关资源
      最近更新 更多