Переопределяющий метод с универсальным типом возврата в Java - PullRequest
1 голос
/ 28 сентября 2011

При использовании обобщенных типов в возвращаемом типе у меня возникают проблемы с расширением родительского класса, как показано в следующем примере.

Как вы знаете, без обобщений следующий пример будет скомпилирован нормально, но он не будет безопасным по типу, потому что его тип должен быть 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);
    }
}

Ответы [ 3 ]

3 голосов
/ 28 сентября 2011

Проблема здесь в том, что 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<String> и реализуется в терминах нисходящего потока AbstractReader<byte[]>. Обратите внимание, что он явно не требует ByteArrayReader - любой старый AbstractReader<byte[]> будет работать.

2 голосов
/ 28 сентября 2011

Вместо наследования можно использовать шаблон проектирования декоратора:

class StringReader {
    private ByteArrayReader bar;

    public StringReader(ByteArrayReader bar) {
        this.bar = bar
    }

    public String readNext() {
        return new String(this.bar.readNext());
    }
}
0 голосов
/ 28 сентября 2011

Ваши проблемы пытаются сказать вам, что это не очень хорошее использование наследования. StringReader определенно не имеет отношения is-to к ByteArrayReader. Если между ними есть какая-то общая функциональность, это всего лишь деталь реализации. Любой такой общий код должен быть передан в AbstractReader, из которого оба должны расширяться напрямую. Тогда абстрактный класс правильно содержит код, общий для его подклассов, и StringReader и ByteArrayReader правильно не связаны, кроме того, что являются реализациями того же самого (предположительно Reader).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...