什么是协变返回类型?


105

Java中的协变返回类型是什么?在一般的面向对象编程中?


5
这篇博客文章(blogs.oracle.com/sundararajan/entry/…)进行了解释,只是在这里汇总了知识库。
Akhil Jain13年

@AkhilJain:该博客文章精彩而简单。这是我所见过的关于Java如何支持协变返回类型的最好的示例说明。
kevinarpe

@kevinarpe谢谢,我很高兴对很多人有帮助。
阿希尔·Ja那

Answers:


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()视为Method<Void, Object>,并询问是否可以将更具体Method<Void, MyFoo>的定义分配给该父类型。当且仅当Java方法的返回类型是协变的时才是。
Andrzej Doyle

38

这是另一个简单的例子:

Animal

public class Animal {

    protected Food seekFood() {

        return new Food();
    }
}

Dog

public class Dog extends Animal {

    @Override
    protected Food seekFood() {

        return new DogFood();
    }
}

这是可能的修改的返回类型DogseekFood()方法DogFood-的一个子类Food,如下所示:

@Override
protected DogFood seekFood() {

    return new DogFood();
}

这完全是合法的覆盖,并且DogseekFood()方法的返回类型称为协变返回类型


8

从JDK 1.5发行版开始,Java中引入了协变类型。我将用一个简单的例子向您解释:当我们重写一个函数时,允许该函数对其行为进行更改,这是您在大多数书籍中都会读到的,但是它们{作者}却错过了是我们也可以更改返回类型。检查下面的链接以弄清楚,我们可以更改返回类型,只要可以将其分配为方法的基本版本的返回类型即可。

因此,此返回派生类型的功能称为COVARIANT ...

重写方法的返回类型可以不同吗?


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()返回不相关的类型AChild.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;
    }
}

函数.java

@FunctionalInterface
public interface Function<T, R> {

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

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

0

在Java5之前,无法通过更改返回类型来覆盖任何方法。但是现在,从Java5开始,如果子类覆盖了返回类型为Non-Primitive的任何方法,但是它将其返回类型更改为子类类型,则可以通过更改返回类型来覆盖方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.