Der kovariante Rückgabetyp in Java

1. Übersicht

In diesem Tutorial werden wir uns den kovarianten Rückgabetyp in Java genauer ansehen. Bevor wir die Kovarianz aus der Sicht des Rückgabetyps untersuchen, wollen wir sehen, was das bedeutet.

2. Kovarianz

Kovarianz kann als Vertrag darüber betrachtet werden, wie ein Subtyp akzeptiert wird, wenn nur der Supertyp definiert ist.

Betrachten wir einige grundlegende Beispiele für Kovarianz:

List integerList = new ArrayList(); List doubleList = new ArrayList();

So Kovarianz Mittel können wir bestimmte Elemente über ihren Supertyp definiert zugreifen . Es ist uns jedoch nicht gestattet, Elemente in ein kovariantes System einzufügen , da der Compiler den tatsächlichen Typ der generischen Struktur nicht bestimmen würde.

3. Der kovariante Rückgabetyp

Der kovariante Rückgabetyp ist - wenn wir eine Methode überschreiben - der Rückgabetyp als Subtyp des Typs der überschriebenen Methode .

Um dies in die Praxis umzusetzen, nehmen wir eine einfache Producer- Klasse mit einer produzieren () -Methode . Standardmäßig wird eine Zeichenfolge als Objekt zurückgegeben , um den untergeordneten Klassen Flexibilität zu bieten:

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

Aufgrund des Objekts als Rückgabetyp können wir einen konkreteren Rückgabetyp in der untergeordneten Klasse haben. Dies ist der kovariante Rückgabetyp und erzeugt Zahlen aus Zeichenfolgen:

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

4. Die Verwendung der Struktur

Die Hauptidee hinter den kovarianten Rückgabetypen besteht darin, die Liskov-Substitution zu unterstützen.

Betrachten wir zum Beispiel das folgende Herstellerszenario:

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

Nach dem Wechsel zu IntegerProducer kann die Geschäftslogik, die das Ergebnis tatsächlich erzeugt, dieselbe bleiben:

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

Wir verweisen jedoch immer noch über ein Objekt auf das Ergebnis . Wann immer wir anfangen, einen expliziten Verweis auf den IntegerProducer zu verwenden, können wir das Ergebnis als Integer abrufen, ohne es herunterzuspielen:

@Test public void whenInputIsSupported_thenIntegerProducerCreatesIntegerWithoutCasting() { String integerAsString = "42"; IntegerProducer producer = new IntegerProducer(); Integer result = producer.produce(integerAsString); assertEquals(Integer.parseInt(integerAsString), result); }

Ein bekanntes Szenario ist die Object # -Klonmethode , die standardmäßig ein Objekt zurückgibt . Immer wenn wir die clone () -Methode überschreiben, können wir durch die Möglichkeit kovarianter Rückgabetypen ein konkreteres Rückgabeobjekt als das Objekt selbst haben.

5. Schlussfolgerung

In diesem Artikel haben wir gesehen, was die Kovarianz- und Kovarianten-Rückgabetypen sind und wie sie sich in Java verhalten.

Wie immer ist der Code auf GitHub verfügbar.