Generieke constructeurs in Java

1. Overzicht

We hebben eerder de basisprincipes van Java Generics besproken. In deze tutorial zullen we Generic Constructors in Java bekijken.

Een generieke constructor is een constructor die ten minste één parameter van een generiek type heeft.

We zullen zien dat generieke constructors niet in een generieke klasse hoeven te zitten, en niet alle constructors in een generieke klasse hoeven generiek te zijn.

2. Niet-generieke klasse

Ten eerste hebben we een eenvoudige les Binnenkomst, wat geen generieke klasse is:

public class Entry {privé String-gegevens; private int rang; }

In deze klasse voegen we twee constructors toe: een basisconstructor met twee parameters en een generieke constructor.

2.1. Basisconstructeur

De eerste Binnenkomst constructor is een eenvoudige constructor met twee parameters:

openbare invoer (String data, int rank) {this.data = data; this.rank = rang; }

Laten we nu deze basisconstructor gebruiken om een Binnenkomst voorwerp:

@Test openbare leegte gegevenNonGenericConstructor_whenCreateNonGenericEntry_thenOK () {Entry entry = nieuwe entry ("sample", 1); assertEquals ("sample", entry.getData ()); assertEquals (1, entry.getRank ()); }

2.2. Generieke constructor

Vervolgens is onze tweede constructor een generieke constructor:

openbare invoer (E-element) {this.data = element.toString (); this.rank = element.getRank (); }

Hoewel de Binnenkomst class is niet generiek, het heeft een generieke constructor, omdat het een parameter heeft element van het type E..

Het generieke type E. is begrensd en zou beide moeten implementeren Rankbaar en Serialiseerbaar interfaces.

Laten we nu eens kijken naar de Rankbaar interface, die één methode heeft:

openbare interface Rankable {public int getRank (); }

En stel dat we een klas hebben Product dat implementeert de Rankbaar koppel:

public class Product implementeert Rankable, Serializable {private String name; particuliere dubbele prijs; particuliere int verkoop; openbaar product (tekenreeksnaam, dubbele prijs) {this.name = naam; this.price = prijs; } @Override public int getRank () {retourverkopen; }}

We kunnen dan de generieke constructor gebruiken om Binnenkomst objecten met behulp van een Product:

@Test openbare ongeldig gegevenGenericConstructor_whenCreateNonGenericEntry_thenOK () {Product product = nieuw product ("melk", 2.5); product.setSales (30); Entry entry = nieuwe Entry (product); assertEquals (product.toString (), entry.getData ()); assertEquals (30, entry.getRank ()); }

3. Generieke klasse

Vervolgens zullen we een generieke klasse bekijken met de naam GenericEntry:

openbare klasse GenericEntry {privé T-gegevens; private int rang; }

We zullen ook dezelfde twee soorten constructors toevoegen als in de vorige sectie in deze klasse.

3.1. Basisconstructeur

Laten we eerst een eenvoudige, niet-generieke constructor schrijven voor onze GenericEntry klasse:

openbare GenericEntry (int rang) {this.rank = rang; }

Hoewel GenericEntry is een generieke klasse, dit is een eenvoudige constructor die geen parameter van een generiek type heeft.

Nu kunnen we deze constructor gebruiken om een GenericEntry:

@Test openbare leegte gegevenNonGenericConstructor_whenCreateGenericEntry_thenOK () {GenericEntry entry = nieuwe GenericEntry (1); assertNull (entry.getData ()); assertEquals (1, entry.getRank ()); }

3.2. Generieke constructor

Laten we vervolgens de tweede constructor aan onze klas toevoegen:

openbare GenericEntry (T data, int rank) {this.data = data; this.rank = rang; }

Dit is een generieke constructor, aangezien het een gegevens parameter van het generieke type T. Merk op dat we niet hoeven toe te voegen in de constructor-declaratie, omdat deze er impliciet is.

Laten we nu onze generieke constructor testen:

@Test openbare ongeldig gegevenGenericConstructor_whenCreateGenericEntry_thenOK () {GenericEntry entry = nieuwe GenericEntry ("sample", 1); assertEquals ("sample", entry.getData ()); assertEquals (1, entry.getRank ()); }

4. Generieke constructor met ander type

In onze generieke klasse kunnen we ook een constructor hebben met een generiek type dat verschilt van het generieke type van de klasse:

openbare GenericEntry (E-element) {this.data = (T) -element; this.rank = element.getRank (); }

Dit GenericEntry constructor heeft een parameter element met type E., die verschilt van de T type. Laten we het in actie zien:

@Test openbare ongeldig gegevenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK () {Product product = nieuw product ("melk", 2.5); product.setSales (30); GenericEntry entry = nieuwe GenericEntry (product); assertEquals (product, entry.getData ()); assertEquals (30, entry.getRank ()); }

Let daar op:

  • In ons voorbeeld hebben we Product (E.) om een GenericEntry van het type Serialiseerbaar (T)
  • We kunnen deze constructor alleen gebruiken als de parameter van type E. kan worden gegoten T

5. Meerdere generieke typen

Vervolgens hebben we de generieke klasse MapEntry met twee generieke typen:

openbare klasse MapEntry {privé K-sleutel; private V-waarde; openbare MapEntry (K-sleutel, V-waarde) {this.key = key; this.value = waarde; }}

MapEntry heeft één generieke constructor met twee parameters, elk van een ander type. Laten we het gebruiken in een eenvoudige unit-test:

@Test openbare leegte gegevenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK () {MapEntry entry = nieuwe MapEntry ("sample", 1); assertEquals ("sample", entry.getKey ()); assertEquals (1, entry.getValue (). intValue ()); }

6. Jokertekens

Ten slotte kunnen we jokertekens gebruiken in een generieke constructor:

public GenericEntry (Optioneel optioneel) {if (optional.isPresent ()) {this.data = (T) optional.get (); this.rank = optional.get (). getRank (); }}

Hier hebben we jokertekens in gebruikt GenericEntry constructor om het Optioneel type:

@Test openbare ongeldig gegevenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK () {Product product = nieuw product ("melk", 2.5); product.setSales (30); Optioneel optioneel = Optioneel.of (product); GenericEntry entry = nieuwe GenericEntry (optioneel); assertEquals (product, entry.getData ()); assertEquals (30, entry.getRank ()); }

Merk op dat we het optionele parametertype zouden moeten kunnen casten (in ons geval, Product) naar de GenericEntry type (in ons geval, Serialiseerbaar).

7. Conclusie

In dit artikel hebben we geleerd hoe we generieke constructors kunnen definiëren en gebruiken in zowel generieke als niet-generieke klassen.

De volledige broncode is te vinden op GitHub.