代码之家  ›  专栏  ›  技术社区  ›  Denys Kniazhev-Support Ukraine

Java:泛型继承混乱

  •  3
  • Denys Kniazhev-Support Ukraine  · 技术社区  · 15 年前

    假设我们有以下课程:

    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
        }
    }
    

    getList 在里面 ChildClass 不编译,输出为:

    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!
        }
    }
    

    所以我把整数转换成数字,就解决了这个问题。

    5 回复  |  直到 7 年前
        1
  •  5
  •   Marc    15 年前

    你的基类应该是:

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

    您没有使用t,而是使用Number类作为参数。

        2
  •  2
  •   Tyler Treat    15 年前

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

        3
  •  2
  •   Pointy    15 年前

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

    public List<T> getList(T t)
    

    ?

        4
  •  1
  •   Damian Leszczyński - Vash    15 年前

    想象中的班级发生了什么。

     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类型相同的数字,如果类有两个相同的方法,则可能会导致一些错误。(未经编译器测试)

     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); 
        }
    }
    

     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;
        }
    
    }
    
        5
  •  0
  •   oiavorskyi    15 年前

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