Что такое ковариантный тип возвращаемого значения?

105

Что такое ковариантный тип возвращаемого значения в Java? В объектно-ориентированном программировании вообще?

Попс
источник
5
это сообщение в блоге ( blogs.oracle.com/sundararajan/entry/… ) объясняет, просто добавляя сюда базу знаний.
Akhil Jain
@AkhilJain: Этот пост в блоге гениален и прост. Это лучшее объяснение на примере, которое я когда-либо видел, того, как Java поддерживает ковариантные возвращаемые типы.
kevinarpe
@kevinarpe, спасибо, я рад, что это помогло многим людям.
Akhil Jain

Ответы:

143

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

Чтобы прояснить это на примере, распространенным случаем является Object.clone()- который объявлен как возвращающий тип Object. Вы можете переопределить это в своем собственном классе следующим образом:

public class MyFoo
{

   ...

   // Note covariant return here, method does not just return Object
   public MyFoo clone()
   {
       // Implementation
   }
}

Преимущество здесь заключается в том, что любой метод, который содержит явную ссылку на объект MyFoo, сможет вызывать clone()и знать (без приведения), что возвращаемое значение является экземпляром MyFoo. Без ковариантных типов возврата необходимо было бы объявить переопределенный метод в MyFoo для возвратаObject - и поэтому вызывающий код должен был бы явно понижать результат вызова метода (даже если бы обе стороны «знали», что это может быть только экземпляр MyFoo ).

Обратите внимание, что в этом нет ничего особенного clone()и что любой переопределенный метод может иметь ковариантный возврат - я использовал его в качестве примера здесь, поскольку это стандартный метод, где это часто бывает полезно.

Анджей Дойл
источник
разве это не должно быть связано с List<Foo>и List<FooBar>?
zinking
2
Это ковариантные типы в более широком смысле, а не просто ковариантный возвращаемый тип, о котором здесь спрашивают. Тем не менее, это тот же основной принцип - вы можете думать об определении верхнего уровня clone()как об a Method<Void, Object>и спрашивать, можно ли Method<Void, MyFoo>присвоить более конкретное определение этому родительскому типу. Так оно и есть, если и только если методы Java ковариантны по типу возвращаемого значения.
Анджей Дойл
38

Вот еще один простой пример:

Animal класс

public class Animal {

    protected Food seekFood() {

        return new Food();
    }
}

Dog класс

public class Dog extends Animal {

    @Override
    protected Food seekFood() {

        return new DogFood();
    }
}

Можно изменить тип возвращаемого значения Dog«s seekFood()метода к DogFood- подкласс Food, как показано ниже:

@Override
protected DogFood seekFood() {

    return new DogFood();
}

Это совершенно законная наиважнейшее, и возвращаемый тип Dog«S seekFood()метод известен как ковариантном типа возвращаемого .

Мохамед АЛУАН
источник
8

Начиная с выпуска JDK 1.5, ковариантные типы были введены в Java. и я объясню вам это на простом примере: когда мы переопределяем функцию, функции разрешается вносить изменения в ее поведение , это то, что вы читаете в большинстве книг, но то, что они {авторы} упускают в том, что мы можем изменить и возвращаемый тип. проверьте ссылку ниже для пояснения, мы можем изменить тип возвращаемого значения, если он может быть назначен типу возврата базовой версии метода.

Итак, эта функция возврата производных типов называется КОВАРИАНТНОЙ ...

Могут ли переопределенные методы отличаться по типу возвращаемого значения?

ПрезидентПратик
источник
7

Ковариантные возвращаемые типы просто означают возвращение собственной ссылки на класс или ссылки на его дочерний класс.

class Parent {
 //it contain data member and data method
}

class Child extends Parent { 
//it contain data member and data method
 //covariant return
  public Parent methodName() {
     return new Parent();
          or 
     return Child();
  }

}
Дхирадж
источник
1
Он также включает случай, когда Parent.foo()возвращает несвязанный тип Aи Child.foo()возвращает тип, Bпроизводный от A.
Дэвис Херринг
2

Чтобы добавить к приведенным выше ответам, переопределение возможно среди ковариантных возвращаемых типов с ограничением, что возвращаемый тип метода переопределения (метод подкласса) должен быть подклассом типа возвращаемого значения переопределенного метода (метод суперкласса). Это действительно начиная с Java 5.

Жизнь Пая
источник
1

Ковариантный тип возвращаемого значения указывает, что тип возвращаемого значения может изменяться в том же направлении, что и подкласс

class One{  
    One get(){return this;}  
}  

class Two extends One{  
  Two get(){return this;}  

void message(){
  System.out.println("After Java5 welcome to covariant return type");
}  

public static void main(String args[]){  
    new Two().get().message();  
}  
}

До Java 5 было невозможно переопределить какой-либо метод путем изменения типа возвращаемого значения. Но теперь, начиная с Java5,

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

Кешав Гера
источник
1
  • Это помогает избежать путаницы при приведении типов, присутствующих в иерархии классов, и тем самым делает код читабельным, удобным и поддерживаемым.
  • Мы можем иметь более конкретные возвращаемые типы при переопределении
    методов.

  • Помощь в предотвращении исключений ClassCastExceptions во время выполнения при возврате

ссылка: www.geeksforgeeks.org

Арун Раадж
источник
0
  • Ковариантный тип возвращаемого значения в java позволяет сузить тип возвращаемого значения переопределенного метода.
  • Эта функция поможет избежать потери качества на стороне клиента. Это позволяет программисту программировать без необходимости проверки типов и преобразования вниз.
  • Ковариантный тип возврата всегда работает только для непримитивных типов возврата.
interface Interviewer {
    default Object submitInterviewStatus() {
        System.out.println("Interviewer:Accept");
        return "Interviewer:Accept";
    }
}
class Manager implements Interviewer {
    @Override
    public String submitInterviewStatus() {
        System.out.println("Manager:Accept");
        return "Manager:Accept";
    }
}
class Project {
    public static void main(String args[]) {
        Interviewer interviewer = new Manager();
        interviewer.submitInterviewStatus();
        Manager mgr = new Manager();
        mgr.submitInterviewStatus();
    }
}

Другой пример взят из Java,

UnaryOperator.java

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}

Function.java

@FunctionalInterface
public interface Function<T, R> {

    ........
    ........
    ........
    ........

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
snr
источник
0

До Java5 было невозможно переопределить какой-либо метод, изменив тип возвращаемого значения. Но теперь, начиная с Java5, можно переопределить метод, изменив тип возвращаемого значения, если подкласс переопределяет любой метод, тип возвращаемого значения которого не является примитивным, но он меняет свой тип возвращаемого значения на тип подкласса.


источник