O que é um tipo de retorno covariante?

105

O que é um tipo de retorno covariante em Java? Em programação orientada a objetos em geral?

Pops
fonte
5
esta postagem do blog ( blogs.oracle.com/sundararajan/entry/… ) explica, apenas adicionando à base de conhecimento aqui.
Akhil Jain de
@AkhilJain: Essa postagem do blog é brilhante e simples. É a melhor explicação por exemplo que já vi sobre como o Java oferece suporte a tipos de retorno covariante.
kevinarpe
@kevinarpe obrigado, fico feliz que seja útil para tantas pessoas.
Akhil Jain

Respostas:

143

Retorno covariante, significa que quando alguém sobrescreve um método, o tipo de retorno do método sobrescrita pode ser um subtipo do tipo de retorno do método sobrescrito.

Para esclarecer isso com um exemplo, um caso comum é Object.clone()- que é declarado para retornar um tipo de Object. Você pode substituir isso em sua própria classe da seguinte maneira:

public class MyFoo
{

   ...

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

O benefício aqui é que qualquer método que contenha uma referência explícita a um objeto MyFoo será capaz de invocar clone()e saber (sem lançar) que o valor de retorno é uma instância de MyFoo. Sem os tipos de retorno covariante, o método sobrescrito em MyFoo teria que ser declarado para retornar Object- e então o código de chamada teria que reduzir explicitamente o resultado da chamada do método (mesmo que ambos os lados "saibam" que só pode ser uma instância de MyFoo )

Observe que não há nada de especial clone()e que qualquer método substituído pode ter um retorno covariante - usei-o como um exemplo aqui, pois é um método padrão onde geralmente é útil.

Andrzej Doyle
fonte
não deveria estar relacionado com List<Foo>e List<FooBar>?
zinking
2
Esses são os tipos covariantes em um sentido mais amplo, e não apenas o tipo de retorno covariante questionado aqui. É o mesmo princípio subjacente, porém - você pode pensar na definição de nível superior de clone()como sendo um Method<Void, Object>e perguntar se o mais específico pode Method<Void, MyFoo>ser atribuído a esse tipo de pai. O que é, se e somente se os métodos Java são covariantes em seu tipo de retorno.
Andrzej Doyle
38

Aqui está outro exemplo simples:

Animal classe

public class Animal {

    protected Food seekFood() {

        return new Food();
    }
}

Dog classe

public class Dog extends Animal {

    @Override
    protected Food seekFood() {

        return new DogFood();
    }
}

É possível modificar o tipo de retorno do Dog's seekFood()método para DogFood- uma subclasse de Food, como mostrado abaixo:

@Override
protected DogFood seekFood() {

    return new DogFood();
}

Isso é perfeitamente um primordial legal, e o tipo de retorno Dogdo seekFood()método é conhecido como tipo de retorno covariant .

Mohamed ALOUANE
fonte
8

A partir do lançamento do JDK 1.5, os tipos covariant foram introduzidos em Java. e vou explicar para você com um caso simples: Quando substituímos uma função, a função tem permissão para fazer alterações em seu comportamento isso é o que você lê na maioria dos livros, mas o que eles {autores} perdem é que podemos alterar o tipo de retorno também. verifique o link abaixo para esclarecimento, podemos alterar o tipo de retorno, desde que possa ser atribuído ao tipo de retorno da versão Base do método.

Portanto, esse recurso de retornar tipos derivados é chamado de COVARIANTE ...

Os métodos substituídos podem diferir no tipo de retorno?

PresidentPratik
fonte
7

Os tipos de retorno covariant simplesmente significam retornar a própria referência de classe ou sua referência de classe filha.

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
fonte
1
Também inclui o caso em que Parent.foo()retorna um tipo não relacionadoA e Child.foo()retorna um tipo Bderivado de A.
Davis Herring
2

Para adicionar às respostas acima, a substituição é possível entre os tipos de retorno co-variantes, com a restrição de que o tipo de retorno do método de substituição (método da subclasse) deve ser uma subclasse do tipo de retorno do método substituído (método da superclasse). Isso é válido do Java 5 em diante.

Vida do pai
fonte
1

O tipo de retorno covariante especifica que o tipo de retorno pode variar na mesma direção da subclasse

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 do Java 5, não era possível substituir nenhum método alterando o tipo de retorno. Mas agora, desde Java5,

é possível sobrescrever o método alterando o tipo de retorno se a subclasse sobrescrever qualquer método cujo tipo de retorno seja Não-Primitivo, mas ele altera seu tipo de retorno para o tipo de subclasse.

Keshav Gera
fonte
1
  • Isso ajuda a evitar a confusão de tipos de conversão presentes na hierarquia de classes, tornando o código legível, utilizável e sustentável.
  • Temos a liberdade de ter tipos de retorno mais específicos ao substituir
    métodos.

  • Ajuda na prevenção de ClassCastExceptions em tempo de execução em devoluções

referência: www.geeksforgeeks.org

Arun Raaj
fonte
0
  • O tipo de retorno covariant em java permite estreitar o tipo de retorno do método substituído.
  • Esse recurso ajudará a evitar downcast no lado do cliente. Ele permite que o programador programe sem a necessidade de verificação de tipo e conversão para baixo.
  • O tipo de retorno covariante sempre funciona apenas para tipos de retorno não 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();
    }
}

Outro exemplo é 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
fonte
0

Antes do Java5, não era possível substituir nenhum método alterando o tipo de retorno. Mas agora, desde o Java5, é possível sobrescrever o método alterando o tipo de retorno se a subclasse sobrescrever qualquer método cujo tipo de retorno seja Não-Primitivo, mas altere seu tipo de retorno para o tipo de subclasse.


fonte