Sissejuhatus üldistesse tüüpidesse Java-s: kovariantsus ja vastuolulisus

Tüübid

Java on staatiliselt sisestatud keel, mis tähendab, et enne selle kasutamist peate muutuja ja selle tüübi deklareerima.

Näiteks: int myInteger = 42;

Sisestage üldised tüübid.

Üldised tüübid

Definitsioon: „ Üldine tüüp on üldine klass või liides, mis on tüüpidega parameetriline.”

Põhimõtteliselt võimaldavad üldised tüübid kirjutada üldise, üldise klassi (või meetodi), mis töötab erinevate tüüpidega, võimaldades koodi uuesti kasutada.

Selle asemel, täpsustades obj, et sellise inttüübi või Stringtüüp, või mingit muud tüüpi, siis määratlevad Boxklassi nõustuda parameeter <; T>. Seejärel saate nselle üldise tüübi esindamiseks kasutada klassi T mis tahes osas.

Sisestage nüüd kovariantsus ja vastuolulisus.

Kovariantsus ja vastuolulisus

Definitsioon

Dispersioon viitab sellele, kuidas keerukamate tüüpide vaheline alltüüpimine on seotud nende komponentide (allika) vahelise alltüüpimisega.

Kovariantsuse ja vastuolulisuse lihtne meeldejääv (ja äärmiselt mitteametlik) määratlus on:

  • Kovariantsus: aktsepteerige alamtüüpe
  • Vastuolulisus: aktsepteerige supertüüpe

Massiivid

Javas on massiivid kovariaalsed , millel on kaks tähendust.

Esiteks T[]võib tüüpi massiiv sisaldada tüübi Tja selle alamtüüpide elemente .

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

Teiseks on tüüpi massiiv S[]alamtüüp T[]if Son alamtüüp T.

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

Siiski on oluline meeles pidada, et: (1) numArron viide tüübile Number[]"tegelik objekt intArr" Integer[].

Seetõttu kompileerib järgmine rida suurepäraselt, kuid annab tööaja ArrayStoreException(hunnikureostuse tõttu):

numArr[0] = 1.23; // Not ok

See tekitab käitamise erandi, kuna Java teab käitusajal, et “tegelik objekt” intArron tegelikult massiiv Integer.

Üldised

Üldiste tüüpide korral pole Java tüübi kustutamise tõttu runtime ajal võimalik teada tüübiparameetrite tüübiinfot. Seetõttu ei saa see tööajal kaitsta kuhjaga saastumise eest.

Sellisena on geneerilised ravimid muutumatud.

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

Tüüpparameetrid peavad täpselt kokku sobima, et kaitsta kuhjasaaste eest.

Kuid sisestage metamärgid.

Metamärgid, kovariantsus ja vastuolulisus

Metamärkide abil on võimalik, et geneerilised ravimid toetavad kovariantsust ja vastuolulisust.

Eelmise näite kohandamine, saame selle, mis töötab!

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

Küsimärk “?” viitab metamärgile, mis tähistab tundmatut tüüpi. See võib olla madalama piiriga, mis piirab tundmatut tüüpi konkreetseks tüübiks või selle ülatüübiks.

Seetõttu tähendab 2. rida ? super Integer"mis tahes tüüpi, mis on täisarvu tüüp või selle supertüüp".

Kasutades saab ka ülemise piiriga metamärki, mis piirab tundmatut tüüpi konkreetseks tüübiks või selle alamtüübiks ? extends Integer.

Ainult lugemiseks ja kirjutamiseks

Kovariantsus ja vastuolulisus annavad huvitavaid tulemusi. Kovariaanitüübid on kirjutuskaitstud, samas kui vastuolulised tüübid on kirjutuskaitstud.

Pidage meeles, et kovariaalsed tüübid aktsepteerivad alamtüüpe, nii et 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>.