Различные типы возврата абстрактного метода в java без приведения

Я пытаюсь реализовать и переопределить метод с разными типами возвращаемого значения без необходимости приведения типа возвращаемого значения.

public abstract class A {
public abstract Object getValue(String content);
}

public class B extends A {
public String getValue(String content) {...}
}

public class C extends A {
public int getValue(String content) {...}
}


public class D extends A {
public boolean getValue(String content) {...}
}

// Main loop:
for (A a : allAs)
{
// I want to use the method getValue() and corresponding to the type return a String, int or boolean without casting the return type
}

Мой вопрос: можно ли возвращать разные типы без принуждения? Как абстрактный метод выглядит для решения проблемы?

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


person erwingun2010    schedule 23.02.2013    source источник
comment
Вы не можете переопределить на основе возвращаемых типов.   -  person Brian Roach    schedule 23.02.2013
comment
И эта программа не будет компилироваться   -  person Pradeep Simha    schedule 23.02.2013


Ответы (4)


В вашем примере классы C и D не будут компилироваться. Переопределенные методы в них нарушают принцип подстановки Лисков, иначе говоря, их возвращаемый тип несовместим с их родительским классом. То, что вы хотите сделать, может быть достигнуто с помощью дженериков, если вы готовы отказаться от использования примитивов в качестве возвращаемого типа.

abstract class A<T> {
    public abstract T getValue(String content);
}

class B extends A<String> {
    public String getValue(String content) { }
}

class C extends A<Integer> {
    public Integer getValue(String content) { }
}

class D extends A<Boolean> {
    public Boolean getValue(String content) { }
}
person Perception    schedule 23.02.2013
comment
Спасибо. Этот код может работать. Однако возвращаемый тип getValue() является объектом, поэтому я должен его использовать. - person erwingun2010; 23.02.2013
comment
@ erwingun2010 Если ваш метод имеет тип возвращаемого значения Object, возможно, вы неправильно создаете экземпляр своего класса. Сделайте следующее: A<String> bInstance = new B(); Если вы не добавите тип в объявление A, ваши абстрактные методы вернут Object. - person fiskeben; 03.04.2014

То, что вы описываете, вообще невозможно. Однако, если подкласс возвращает «более узкий» подтип возвращаемого метода суперкласса, это называется «ковариантным возвращаемым типом» и разрешено в Java, начиная с JDK 1.5. Однако, основываясь на вашем примере, я не думаю, что ковариантный возврат - это то, что вы ищете.

Я предполагаю, что вы хотите

for (A a : allAs)
{
    String b = a.getValue();
    int    c = a.getValue();
}

Проблема здесь, конечно, в том, что компилятор не может узнать во время компиляции, какое из этих двух утверждений верно, и они не могут быть оба правильными.

person Jim Garrison    schedule 23.02.2013
comment
Это именно то, что я хочу. Я до сих пор не понимаю, почему компилятор не может знать во время компиляции, какой возвращаемый тип является правильным. Когда я инициализирую allAs, я использую => allAs.add(new B()); allAs.add(новый C()); - person erwingun2010; 23.02.2013
comment
В примере, который я показал, оба оператора внутри цикла относятся к одному экземпляру A, который не может одновременно быть и B, и C. Как компилятор должен знать, что это такое, поскольку это не происходит до времени выполнения? - person Jim Garrison; 23.02.2013

Вы можете использовать дженерики.

public abstract class A<T> {
   public abstract T getValue(String content);
}

public class B extends A<String> {
   public String getValue(String content) {...}
}

и т. д. int не работает в качестве возвращаемого типа для этого, но Integer будет.

Я не печатаю в компиляторе, поэтому могут быть опечатки...

Как заметили Джим и Крис, если вы зацикливаетесь на As, вы можете получить только результат «A», то есть Object.

person user949300    schedule 23.02.2013

В вашем примере определение class B в порядке, так как String является подклассом Object. Два других не скомпилируются, так как это примитивные типы. Вы можете заменить их на Integer и Boolean, чтобы решить эту проблему.

Что касается вашего основного цикла, если вы перебираете их как ссылки на A, вы сможете использовать только определение метода A, которое возвращает Object.

person Krease    schedule 23.02.2013