En introduktion til generiske typer i Java: kovarians og kontrast

Typer

Java er et statisk skrevet sprog, hvilket betyder, at du først skal erklære en variabel og dens type, før du bruger den.

For eksempel: int myInteger = 42;

Indtast generiske typer.

Generiske typer

Definition: "En generisk type er en generisk klasse eller grænseflade, der er parametreret over typer."

I det væsentlige giver generiske typer dig mulighed for at skrive en generel, generisk klasse (eller metode), der fungerer med forskellige typer, hvilket giver mulighed for genbrug af kode.

I stedet for at angive objat være af en inttype eller en Stringtype eller en hvilken som helst anden type, definerer du Boxklassen til at acceptere en typeparameter <; T>. Derefter kan du nbruge T til at repræsentere den generiske type i en hvilken som helst del inden for din klasse.

Indtast nu kovarians og kontrast.

Kovarians og kontravarians

Definition

Varians henviser til, hvordan undertypning mellem mere komplekse typer relaterer til undertypning mellem deres komponenter (kilde).

En let at huske (og ekstremt uformel) definition af kovarians og kontravarans er:

  • Kovarians: accepter undertyper
  • Kontrast: accepter supertyper

Arrays

I Java er arrays kovariante , hvilket har to implikationer.

For det første kan en matrix af typen T[]indeholde elementer af typen Tog dens undertyper.

Number[] nums = new Number[5];nums[0] = new Integer(1); // Oknums[1] = new Double(2.0); // Ok

For det andet er en matrix af typen S[]en undertype af T[]hvis Ser en undertype af T.

Integer[] intArr = new Integer[5];Number[] numArr = intArr; // Ok

Det er dog vigtigt at huske, at: (1) numArrer en reference til referencetypen Number[]til det "faktiske objekt" intArraf "faktiske type" Integer[].

Derfor vil følgende linje kompilere fint, men producere en runtime ArrayStoreException(på grund af forurening af dynger):

numArr[0] = 1.23; // Not ok

Det producerer en runtime-undtagelse, fordi Java ved runtime ved, at det "faktiske objekt" intArrfaktisk er en matrix af Integer.

Generiske stoffer

Med generiske typer har Java ingen måde at kende typeoplysningerne om typeparametre på runtime på grund af sletning af typen. Derfor kan den ikke beskytte mod dyngeforurening ved kørsel.

Som sådan er generiske stoffer uforanderlige.

ArrayList intArrList = new ArrayList();ArrayList numArrList = intArrList; // Not okArrayList anotherIntArrList = intArrList; // Ok

Typeparametrene skal matche nøjagtigt for at beskytte mod dyngeforurening.

Men indtast wildcards.

Jokertegn, kovarians og kontrast

Med jokertegn er det muligt for generiske stoffer at understøtte kovarians og kontrast.

Tilpasning af det foregående eksempel får vi dette, hvilket fungerer!

ArrayList intArrList = new ArrayList();ArrayList numArrList = intArrList; // Ok

Spørgsmålstegnet “?” henviser til et jokertegn, der repræsenterer en ukendt type. Det kan være lavere afgrænset, hvilket begrænser den ukendte type til at være en bestemt type eller dens supertype.

Derfor, i linje 2, ? super Integeroversættes til "enhver type, der er en heltalstype eller dens supertype".

Du kunne også begrænse wildcardet, som begrænser den ukendte type til at være en bestemt type eller dens undertype ved hjælp af ? extends Integer.

Skrivebeskyttet og skrivebeskyttet

Kovarians og kontravarans giver nogle interessante resultater. Kovariante typer er skrivebeskyttede, mens modstridende typer er skrivebeskyttede.

Husk, at covariant-typer accepterer undertyper, så ArrayList er> can contain any object that is either of a Number type or its subtype.

In this example, line 9 works, because we can be certain that whatever we get from the ArrayList can be upcasted to a Number type (because if it extends Number, by definition, it is a Number).

But nums.add() doesn’t work, because we cannot be sure of the “actual type” of the object. All we know is that it must be a Number or its subtypes (e.g. Integer, Double, Long, etc.).

With contravariance, the converse is true.

Line 9 works, because we can be certain that whatever the “actual type” of the object is, it must be Integer or its supertype, and thus accept an Integer object.

But line 10 doesn’t work, because we cannot be sure that we will get an Integer. For instance, nums could be referencing an ArrayList of Objects.

Applications

Therefore, since covariant types are read-only and contravariant types are write-only (loosely speaking), we can derive the following rule of thumb: “Producer extends, consumer super”.

A producer-like object that produces objects of type T can be of type parameter T>, while a consumer-like object that consumes objects oftype T can be of type parameter super T>.