Generiske konstruktører i Java
1. Oversikt
Vi har tidligere diskutert det grunnleggende om Java Generics. I denne opplæringen tar vi en titt på Generic Constructors i Java.
En generisk konstruktør er en konstruktør som har minst en parameter av en generisk type.
Vi får se at generiske konstruktører ikke trenger å være i en generisk klasse, og ikke alle konstruktører i en generisk klasse må være generiske.
2. Ikke-generisk klasse
Først har vi en enkel klasse Inngang, som ikke er en generisk klasse:
offentlig klasse Oppføring {private String data; privat int rang; }
I denne klassen legger vi til to konstruktører: en grunnleggende konstruktør med to parametere og en generisk konstruktør.
2.1. Grunnleggende konstruktør
Den første Inngang constructor er en enkel konstruktør med to parametere:
offentlig oppføring (String data, int rang) {this.data = data; this.rank = rang; }
La oss nå bruke denne grunnleggende konstruktøren til å lage en Inngang gjenstand:
@Test public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK () {Entry entry = new Entry ("sample", 1); assertEquals ("sample", entry.getData ()); assertEquals (1, entry.getRank ()); }
2.2. Generisk konstruktør
Deretter er vår andre konstruktør en generisk konstruktør:
public Entry (E element) {this.data = element.toString (); this.rank = element.getRank (); }
Selv om Inngang klasse er ikke generisk, den har en generisk konstruktør, siden den har en parameter element av typen E.
Den generiske typen E er avgrenset og skal implementere begge deler Rangering og Serialiserbar grensesnitt.
La oss ta en titt på Rangering grensesnitt, som har en metode:
offentlig grensesnitt Rangering {public int getRank (); }
Anta at vi har en klasse Produkt som implementerer Rangering grensesnitt:
offentlig klasse Produktredskaper Rangable, Serializable {private String name; privat dobbel pris; private int salg; offentlig produkt (strengnavn, dobbel pris) {this.name = navn; dette.pris = pris; } @ Override public int getRank () {retur salg; }}
Vi kan da bruke den generiske konstruktøren til å lage Inngang gjenstander som bruker en Produkt:
@Test offentlig ugyldighet gittGenericConstructor_whenCreateNonGenericEntry_thenOK () {Produktprodukt = nytt produkt ("melk", 2.5); product.setSales (30); Oppføringsoppføring = ny oppføring (produkt); assertEquals (product.toString (), entry.getData ()); assertEquals (30, entry.getRank ()); }
3. Generisk klasse
Deretter tar vi en titt på en generisk klasse som heter GenericEntry:
offentlig klasse GenericEntry {private T-data; privat int rang; }
Vi legger til de samme to typene konstruktører som forrige avsnitt i denne klassen.
3.1. Grunnleggende konstruktør
La oss først skrive en enkel, ikke-generisk konstruktør for vår GenericEntry klasse:
offentlig GenericEntry (int rang) {this.rank = rang; }
Selv om GenericEntry er en generisk klasse, dette er en enkel konstruktør som ikke har en parameter av en generisk type.
Nå kan vi bruke denne konstruktøren til å lage en GenericEntry:
@Test public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK () {GenericEntry entry = new GenericEntry (1); assertNull (entry.getData ()); assertEquals (1, entry.getRank ()); }
3.2. Generisk konstruktør
La oss deretter legge til den andre konstruktøren i klassen vår:
offentlig GenericEntry (T-data, int-rangering) {this.data = data; this.rank = rang; }
Dette er en generisk konstruktør, da den har en data parameter av den generiske typen T. Merk at vi ikke trenger å legge til i konstruktørerklæringen, da den implisitt er der.
La oss nå teste den generiske konstruktøren vår:
@Test offentlig ugyldighet gittGenericConstructor_whenCreateGenericEntry_thenOK () {GenericEntry entry = new GenericEntry ("sample", 1); assertEquals ("sample", entry.getData ()); assertEquals (1, entry.getRank ()); }
4. Generisk konstruktør med forskjellig type
I vår generiske klasse kan vi også ha en konstruktør med en generisk type som er forskjellig fra klassens generiske type:
public GenericEntry (E element) {this.data = (T) element; this.rank = element.getRank (); }
Dette GenericEntry konstruktøren har en parameter element med type E, som er forskjellig fra T type. La oss se det i aksjon:
@Test offentlig ugyldighet gittGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK () {Produkt produkt = nytt produkt ("melk", 2.5); product.setSales (30); GenericEntry entry = new GenericEntry (product); assertEquals (produkt, entry.getData ()); assertEquals (30, entry.getRank ()); }
Noter det:
- I vårt eksempel brukte vi Produkt (E) for å lage en GenericEntry av typen Serialiserbar (T)
- Vi kan bare bruke denne konstruktøren når parameteren av typen E kan støpes til T
5. Flere generiske typer
Deretter har vi generisk klasse MapEntry med to generiske typer:
offentlig klasse MapEntry {privat K-nøkkel; privat V-verdi; offentlig MapEntry (K-tast, V-verdi) {this.key = key; this.value = verdi; }}
MapEntry har en generisk konstruktør med to parametere, hver av en annen type. La oss bruke den i en enkel enhetstest:
@Test public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK () {MapEntry entry = new MapEntry ("sample", 1); assertEquals ("sample", entry.getKey ()); assertEquals (1, entry.getValue (). intValue ()); }
6. Jokertegn
Til slutt kan vi bruke jokertegn i en generisk konstruktør:
public GenericEntry (Valgfritt valgfritt) {if (optional.isPresent ()) {this.data = (T) optional.get (); this.rank = optional.get (). getRank (); }}
Her brukte vi jokertegn i dette GenericEntry konstruktør å binde Valgfri type:
@Test offentlig ugyldighet gittGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK () {Produkt produkt = nytt produkt ("melk", 2.5); product.setSales (30); Valgfritt valgfritt = Valgfritt. Av (produkt); GenericEntry entry = new GenericEntry (valgfritt); assertEquals (produkt, entry.getData ()); assertEquals (30, entry.getRank ()); }
Merk at vi skal kunne kaste den valgfrie parametertypen (i vårt tilfelle Produkt) til GenericEntry type (i vårt tilfelle, Serialiserbar).
7. Konklusjon
I denne artikkelen lærte vi hvordan vi kunne definere og bruke generiske konstruktører i både generiske og ikke-generiske klasser.
Hele kildekoden finner du på GitHub.