【问题标题】:Java: generics inheritance confusionJava:泛型继承混淆
【发布时间】:2011-04-25 22:23:34
【问题描述】:

假设我们有以下类:

public interface MyInterface<T> {
    List<T> getList(T t);
}

abstract class BaseClass<T extends Number> implements MyInterface<T> {
    @Override
    public List<T> getList(Number t) {
        return null;
    }
}

class ChildClass extends BaseClass<Integer> {
    @Override
    public List<Integer> getList(Integer t) {
        return super.getList(t);  //this doesn't compile
    }
}

ChildClass 中的getList 无法编译,输出为:

abstract method getList(T) in com.mypackage.MyInterface cannot be accessed directly

我不明白为什么 BaseClass.getList 方法没有在 ChildClass 中被覆盖。

但让我完全困惑的是使它编译的修复:

class ChildClass extends BaseClass<Integer> {
    @Override
    public List<Integer> getList(Integer t) {
        return super.getList((Number) t);  //Now it compiles!
    }
}

所以我将整数转换为数字,并且解决了这个问题。

谁能解释这段代码发生了什么?

【问题讨论】:

    标签: java oop generics inheritance overriding


    【解决方案1】:

    虚拟课堂上发生了什么。

     abstract class BaseClass<T extends Number> implements MyInterface<T> {
        @Override
        public List<T> getList(Number t) {
            return null;
        }
    }
    

    这个类有一个泛型参数(T),它必须扩展 Number 类并实现接口 MyInterface

    您还尝试覆盖不存在的方法,因为该类不扩展其他任何类。当一个类实现一个接口时,不需要重写接口方法,因为它们只是描述。

    如果我们删除 @override 注释会发生什么。

     abstract class BaseClass<T extends Number> implements MyInterface<T> {
    
        public List<T> getList(Number t) {
            return null;
        }
    }
    

    在这种情况下我们从接口实现方法而是创建一个新的方法,这个方法参数是与T相同类型的Number,它可能会导致类有一些错误两种相同的方法。 (未经编译器测试)

    这个方法的实现应该是这样的

     abstract class BaseClass<T extends Number> implements MyInterface<T> {
    
        public List<T> getList(T t) { //Because T is allready restricted to be Number
            return null;
        }
    }
    

    而且当你指定类型的时候你重写的时候调用这个方法不会有问题

    class ChildClass extends BaseClass<Integer> {
        @Override
        public List<Integer> getList(Integer t) {
            return super.getList(t); 
        }
    }
    

    提前您不必只为返回 null 实现它,然后在某个子类中覆盖它。你可以做的是创建这样的类

     abstract class BaseClass<T extends Number> implements MyInterface<T> {
    
        private List<T> list = new ArrayList<T>(); //The way of initialization is up to You
    
        public List<T> getList() { //Because T is allready restricted to be Number
            return list;
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      正如其他同事指出的那样,问题的原因是父方法的签名不正确。强制转换起作用的原因是编译器处理泛型的方式。如果您使用泛型,它保证不会出现运行时 ClassCastException 问题,但前提是您不进行强制转换。一旦你这样做了,你实际上说编译器要闭嘴,因为你更清楚你的类型到底是什么。但是,在此之后,您可能会在运行时获得 ClassCastException(在这种情况下我假设不是)

      【讨论】:

        【解决方案3】:

        为什么超类方法没有定义为

        public List<T> getList(T t)
        

        ?

        【讨论】:

          【解决方案4】:

          您的基类应如下所示:

          abstract class BaseClass<T extends Number> implements MyInterface<T> {
              @Override
              public List<T> getList(T t) {
                  return null;
              }
          }
          

          您使用的不是 T,而是 Number 类作为参数。

          【讨论】:

          • 你说得对,我应该使用 T。但是,为什么将 Integer 转换为 Number 可以解决它?
          • 因为你调用了getList(Integer t),它引用了接口(没有实现)的getList(T t)。 getList(Number t) 是一个重载函数,但不是最佳匹配。
          • 好的,这是有道理的。谢谢!
          【解决方案5】:

          它不会被覆盖,因为抽象方法接受一个数字作为参数,而具体方法接受一个整数。它们必须相同才能覆盖。

          您应该更改您的抽象类实现以将类型 T 作为参数。

          【讨论】:

            猜你喜欢
            • 2012-09-13
            • 2015-05-13
            • 2016-05-13
            • 2020-01-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多