¿Qué es un tipo de retorno covariante?

105

¿Qué es un tipo de retorno covariante en Java? ¿En la programación orientada a objetos en general?

Pops
fuente
5
esta publicación de blog ( blogs.oracle.com/sundararajan/entry/… ) explica, simplemente agregando a la base de conocimientos aquí.
Akhil Jain
@AkhilJain: Esa publicación de blog es brillante y simple. Es la mejor explicación por ejemplo que he visto de cómo Java admite tipos de retorno covariantes.
kevinarpe
@kevinarpe gracias, me alegro de que sea útil para tanta gente.
Akhil Jain

Respuestas:

143

Retorno covariante, significa que cuando uno anula un método, se permite que el tipo de retorno del método anulado sea un subtipo del tipo de retorno del método anulado.

Para aclarar esto con un ejemplo, un caso común es Object.clone()- que se declara para devolver un tipo de Object. Puede anular esto en su propia clase de la siguiente manera:

public class MyFoo
{

   ...

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

El beneficio aquí es que cualquier método que tenga una referencia explícita a un objeto MyFoo podrá invocar clone()y saber (sin conversión) que el valor de retorno es una instancia de MyFoo. Sin tipos de devolución covariantes, el método anulado en MyFoo tendría que declararse para regresar Object, por lo que el código de llamada tendría que rebajar explícitamente el resultado de la llamada al método (incluso aunque ambos lados "saben" que solo puede ser una instancia de MyFoo ).

Tenga en cuenta que no hay nada especial clone()y que cualquier método anulado puede tener un retorno covariante; lo usé como ejemplo aquí, ya que es un método estándar donde a menudo es útil.

Andrzej Doyle
fuente
¿No se supone que está relacionado con List<Foo>y List<FooBar>?
zinking el
2
Son tipos covariantes en un sentido más amplio en lugar de solo el tipo de retorno covariante que se pregunta aquí. Sin embargo, es el mismo principio subyacente: puede pensar en la definición de nivel superior de clone()como a Method<Void, Object>, y preguntarse si el más específico Method<Void, MyFoo>se puede asignar a ese tipo de padre. Lo cual es, si y solo si los métodos Java son covariantes en su tipo de retorno.
Andrzej Doyle
38

Aquí hay otro ejemplo simple:

Animal clase

public class Animal {

    protected Food seekFood() {

        return new Food();
    }
}

Dog clase

public class Dog extends Animal {

    @Override
    protected Food seekFood() {

        return new DogFood();
    }
}

Es posible modificar el tipo de retorno del método Dog's seekFood()a DogFooduna subclase de Food, como se muestra a continuación:

@Override
protected DogFood seekFood() {

    return new DogFood();
}

Eso es perfectamente legal un primordial, y el tipo de retorno de Dog's seekFood()método se conoce como tipo de retorno covariantes .

Mohamed ALOUANE
fuente
8

Desde el lanzamiento de JDK 1.5, se introdujeron los tipos covariantes en Java. y te lo explicaré con un caso simple: cuando anulamos una función, la función puede realizar cambios en su comportamiento, eso es lo que puedes leer en la mayoría de los libros, pero lo que los {autores} se pierden es que también podemos cambiar el tipo de retorno. Consulte el enlace a continuación para obtener una aclaración, podemos cambiar el tipo de devolución siempre que se pueda asignar al tipo de devolución de la versión base del método.

Entonces, esta característica de devolver tipos derivados se llama COVARIANT ...

¿Pueden los métodos anulados diferir en el tipo de retorno?

PresidentePratik
fuente
7

Los tipos de retorno covariantes simplemente significan devolver la propia referencia de clase o su referencia de clase secundaria.

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

}
Dhiraj
fuente
1
También incluye el caso en el que Parent.foo()devuelve un tipo no relacionadoA y Child.foo()devuelve un tipo Bderivado de A.
Davis Herring
2

Para agregar a las respuestas anteriores, es posible anular entre los tipos de retorno covariantes, con la restricción de que el tipo de retorno del método de anulación (método de subclase) debe ser una subclase del tipo de retorno del método anulado (método de superclase). Esto es válido desde Java 5 en adelante.

Vida de pai
fuente
1

El tipo de retorno covariante especifica que el tipo de retorno puede variar en la misma dirección que la subclase

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

Antes de Java 5, no era posible anular ningún método cambiando el tipo de retorno. Pero ahora, desde Java5,

es posible anular el método cambiando el tipo de retorno si la subclase anula cualquier método cuyo tipo de retorno sea No primitivo pero cambia su tipo de retorno a tipo de subclase.

Keshav Gera
fuente
1
  • Ayuda a evitar las conversiones de tipos confusas presentes en la jerarquía de clases y, por lo tanto, hace que el código sea legible, utilizable y mantenible.
  • Tenemos la libertad de tener tipos de retorno más específicos al anular
    métodos.

  • Ayuda para prevenir ClassCastExceptions en tiempo de ejecución en devoluciones

referencia: www.geeksforgeeks.org

Arun Raaj
fuente
0
  • El tipo de retorno covariante en Java permite reducir el tipo de retorno del método anulado.
  • Esta característica ayudará a evitar la caída del lado del cliente. Permite al programador programar sin necesidad de verificación de tipos y conversión descendente.
  • El tipo de retorno covariante siempre funciona solo para tipos de retorno no primitivos.
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();
    }
}

Otro ejemplo es de 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
fuente
0

Antes de Java5, no era posible anular ningún método cambiando el tipo de retorno. Pero ahora, desde Java5, es posible anular el método cambiando el tipo de retorno si la subclase anula cualquier método cuyo tipo de retorno sea No primitivo pero cambia su tipo de retorno al tipo de subclase.


fuente