【问题标题】:Overriding method with generic return type in JavaJava中具有泛型返回类型的覆盖方法
【发布时间】:2011-09-28 02:05:30
【问题描述】:

在返回类型中使用泛型时,我无法扩展父类 像下面的例子。

如你所知,没有泛型,下面的例子可以正常编译,但它不是类型安全的,因为它的类型应该是 Object。

有什么明确的解决方案(或模式,或建议,任何有用的东西!)我可以参考吗?

class AbstractReader<T>{
    public abstract T readNext();
}
class ByteArrayReader extends AbstractReader<byte[]>{
    @Override
    public byte[] readNext(){   /*...*/ }
}
class StringReader extends ByteArrayReader {
    @Override
    public String readNext() {  
        /* The return type is incompatible 
           with ByteArrayReader.readNext()! */
        return new String(bytes);
    }
}

【问题讨论】:

    标签: java generics subclassing return-type


    【解决方案1】:

    这里的问题是StringReader 扩展ByteArrayReader 没有意义。您将继承与组合混淆了。

    StringReader 继承自ByteArrayReader 时,您是说它将履行一个合同,该合同说它有一个readNext 方法,该方法返回一个byte[]

    你真正想做的是使用组合而不是继承:

    class StringReader extends AbstractReader<String> {
        private AbstractReader<byte[]> downstream;
    
        public StringReader(AbstractReader<byte[]> downstream) {
            this.downstream = downstream;
        }
    
        public String readNext() {
            return new String(downstream.readNext());
        }
    }
    

    这个StringReader 履行AbstractReader&lt;String&gt; 合约,并在下游AbstractReader&lt;byte[]&gt; 方面实现。请注意,它并不明确要求 ByteArrayReader - 任何旧的 AbstractReader&lt;byte[]&gt; 都可以使用。

    【讨论】:

    • 谢谢。我同意 StringReader 是 AbstractReader。 (如果我的代码编译成功,多态性将无法正常工作。)但是如果 StringReader 和 ByteArrayReader 共享许多函数,您将重复看到类似ReturnType someMethod(Args args){ byteArrayReader.someMethod(args); } 的代码。是不是很奇怪?
    • 是的,有点奇怪。您在这里所做的本质上是将AbstractReader&lt;TypeA&gt; 映射到AbstractReader&lt;TypeB&gt;,因此您(不幸的是)需要实现每个方法。如果有一种简单的方法来映射类型参数,您可以使用反射来实现这一点,但它会很慢、很难看并且完全无法维护。
    【解决方案2】:

    您可以使用装饰器设计模式而不是继承:

    class StringReader {
        private ByteArrayReader bar;
    
        public StringReader(ByteArrayReader bar) {
            this.bar = bar
        }
    
        public String readNext() {
            return new String(this.bar.readNext());
        }
    }
    

    【讨论】:

    • 感谢您的建议。我也认为在这种情况下使用组合是最好的。但是,如果 StringReader 和 ByteArrayReader 共享很多方法,那么装饰器就会有这样的重复代码:ReturnType someMethod(Arg args){ byteArray.someMethod(); }这是否不可避免?
    • 是的,这可能会导致重复代码,但也会导致更简洁的实现!
    【解决方案3】:

    您的问题试图告诉您的是,这不是很好地使用继承。 StringReader 与 ByteArrayReader 绝对没有 is-a 关系。如果它们之间有一些共同的功能,那只是一个实现细节。任何这样的通用代码都应该被推送到 AbstractReader 中,两者都应该直接从中扩展。然后抽象类正确地包含其子类共有的代码,并且 StringReader 和 ByteArrayReader 除了是同一事物的实现(可能是 Reader)之外,正确地不相关。

    【讨论】:

    • 谢谢。我的示例代码令人困惑,但我可以从您的回答中找出问题所在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-16
    • 2014-04-18
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多