Java >> Java tutorial >  >> Tag >> return

Covariant Return Type i Java

1. Oversigt

I denne tutorial skal vi se nærmere på den kovariante returtype i Java. Før vi undersøger kovarians fra returtypens synspunkt, lad os se, hvad det betyder.

2. Kovarians

Kovarians kan betragtes som en kontrakt for, hvordan en undertype accepteres, når kun supertypen er defineret.

Lad os overveje et par grundlæggende eksempler på kovarians:

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

kovarians betyder, at vi kan få adgang til specifikke elementer defineret via deres supertype . Men vi har ikke lov til at sætte elementer ind i et kovariant system , da compileren ikke ville kunne bestemme den faktiske type af den generiske struktur.

3. Den kovariante returtype

Den kovariante returtype er – når vi tilsidesætter en metode – det, der tillader returtypen at være undertypen af ​​typen af ​​den tilsidesatte metode .

For at omsætte dette til praksis, lad os tage en simpel Producer klasse med en produce() metode. Som standard returnerer den en streng som et objekt at give fleksibilitet til børneklasserne:

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

Som et resultat af Objektet  som returtype kan vi have en mere konkret returtype i børneklassen. Det vil være den kovariante returtype og vil producere tal fra tegnsekvenser:

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

4. Brugen af ​​strukturen

Hovedideen bag de kovariante afkasttyper er at understøtte Liskov-substitutionen.

Lad os f.eks. overveje følgende producentscenario:

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

Efter ændring til IntegerProducer , kan den forretningslogik, der faktisk producerer resultatet, forblive den samme:

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

Vi refererer dog stadig til resultatet via et Objekt. Hver gang vi begynder at bruge en eksplicit henvisning til IntegerProducer,  vi kan hente resultatet som et heltal uden nedkastning:

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

    Integer result = producer.produce(integerAsString);

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

Et velkendt scenarie er Object# klon metode, som returnerer et Objekt som standard. Hver gang vi tilsidesætter clone() metode, giver muligheden for kovariante returtyper os mulighed for at have et mere konkret returobjekt end Objektet  sig selv.

5. Konklusion

I denne artikel så vi, hvad kovarians- og kovariansafkasttyperne er, og hvordan de opfører sig i Java.

Som altid er koden tilgængelig på GitHub.


Java tag