The Covariant Return Type in Java – Java中的协变量返回类型

最后修改: 2020年 6月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’re going to have a closer look at the covariant return type in Java. Before examining covariance from the return type’s point of view, let’s see what that means.

在本教程中,我们将对Java中的协变返回类型进行仔细研究。在从返回类型的角度考察协变性之前,让我们看看这意味着什么。

2. Covariance

2.协方差

Covariance can be considered as a contract for how a subtype is accepted when only the supertype is defined.

共变性可以被认为是在只定义了超类型的情况下如何接受子类型的契约。

Let’s consider a couple of basic examples of covariance:

让我们考虑几个关于共变的基本例子。

List<? extends Number> integerList = new ArrayList<Integer>();
List<? extends Number> doubleList = new ArrayList<Double>();

So covariance means, we can access specific elements defined via their supertype. However, we aren’t allowed to put elements into a covariant system, since the compiler would fail to determine the actual type of the generic structure.

所以共变意味着,我们可以访问通过其超类型定义的特定元素。然而,我们不允许将元素放入共变系统中,因为编译器将无法确定通用结构的实际类型。

3. The Covariant Return Type

3.共变返回类型

The covariant return type is – when we override a method – what allows the return type to be the subtype of the type of the overridden method.

共变返回类型是–当我们覆盖一个方法时–允许返回类型是被覆盖方法的类型的子类型

To put this into practice, let’s take a simple Producer class with a produce() method. By default, it returns a String as an Object to provide flexibility for the child classes:

为了将其付诸实践,让我们来看看一个简单的Producer 类,它有一个produce() 方法默认情况下,它返回一个String 作为一个Object ,为子类提供灵活性。

public class Producer {
    public Object produce(String input) {
        Object result = input.toLowerCase();
        return result;
    }
}

As a result of the Object as a return type, we can have a more concrete return type in the child class. That will be the covariant return type and will produce numbers from character sequences:

由于Object作为一个返回类型,我们可以在子类中有一个更具体的返回类型。这将是共变的返回类型,并将从字符序列中产生数字。

public class IntegerProducer extends Producer {
    @Override
    public Integer produce(String input) {
        return Integer.parseInt(input);
    }
}

4. The Usage of the Structure

4.结构的使用

The main idea behind the covariant return types is to support the Liskov substitution.

协变量返回类型的主要思想是支持Liskov替换

For instance, let’s consider the following producer scenario:

例如,让我们考虑以下生产商的情况。

@Test
public void whenInputIsArbitrary_thenProducerProducesString() {
    String arbitraryInput = "just a random text";
    Producer producer = new Producer();

    Object objectOutput = producer.produce(arbitraryInput);

    assertEquals(arbitraryInput, objectOutput);
    assertEquals(String.class, objectOutput.getClass());
}

After changing to IntegerProducer, the business logic which actually produces the result can remain the same:

在改成IntegerProducer后,实际产生结果的业务逻辑可以保持不变。

@Test
public void whenInputIsSupported_thenProducerCreatesInteger() {
    String integerAsString = "42";
    Producer producer = new IntegerProducer();

    Object result = producer.produce(integerAsString);

    assertEquals(Integer.class, result.getClass());
    assertEquals(Integer.parseInt(integerAsString), result);
}

However, we’re still referencing the result via an Object. Whenever we start to use an explicit reference to the IntegerProducer, we can retrieve the result as an Integer without downcasting:

然而,我们仍然通过一个对象来引用结果。每当我们开始使用对IntegerProducer的显式引用时,我们可以将结果作为Integer来检索,而无需降级。

@Test
public void whenInputIsSupported_thenIntegerProducerCreatesIntegerWithoutCasting() {
    String integerAsString = "42";
    IntegerProducer producer = new IntegerProducer();

    Integer result = producer.produce(integerAsString);

    assertEquals(Integer.parseInt(integerAsString), result);
}

A well-known scenario is the Object#clone method, which returns an Object by default. Whenever we override the clone() method, the facility of covariant return types allows us to have a more concrete return object than the Object itself.

一个著名的场景是Object#clone方法,它默认返回一个Object。每当我们覆盖clone() 方法时,共变返回类型的设施允许我们拥有一个比Object 本身更具体的返回对象。

5. Conclusion

5.总结

In this article, we saw what the covariance and covariant return types are and how they behave in Java.

在这篇文章中,我们看到了什么是协方差和协方差返回类型以及它们在Java中的表现。

As always, the code is available over on GitHub.

像往常一样,代码可在GitHub上获得