Johdanto yleisiin Java-tyyppeihin: kovarianssi ja ristiriita

Tyypit

Java on staattisesti kirjoitettu kieli, mikä tarkoittaa, että sinun on ensin ilmoitettava muuttuja ja sen tyyppi ennen sen käyttöä.

Esimerkiksi: int myInteger = 42;

Syötä yleiset tyypit.

Yleiset tyypit

Määritelmä: " Geneerinen tyyppi on yleinen luokka tai käyttöliittymä, joka on parametrisoitu tyyppien yli."

Pohjimmiltaan yleisten tyyppien avulla voit kirjoittaa yleisen, yleisen luokan (tai menetelmän), joka toimii erilaisten tyyppien kanssa, mikä sallii koodin uudelleenkäytön.

Kuin määrittää objolevan sellaisen inttyyppiä tai Stringtyyppiä, tai mikä tahansa muu, määrittelet Boxluokan hyväksyä eräänlainen parametri <, T>. Sitten voit nkäyttää T: tä edustamaan kyseistä geneeristä tyyppiä missä tahansa luokassa.

Anna nyt kovarianssi ja ristiriita.

Kovarianssi ja ristiriita

Määritelmä

Varianssi viittaa siihen, kuinka monimutkaisempien tyyppien välinen alatyyppi liittyy niiden komponenttien (lähteen) väliseen alityyppiin.

Kovarianssin ja ristiriitaisuuden helppo muistaa (ja erittäin epävirallinen) määritelmä on:

  • Kovarianssi: hyväksy alatyypit
  • Vastakkainasetus: hyväksy supertyypit

Taulukot

Java: ssa matriisit ovat kovariaanteja , millä on 2 merkitystä.

Ensinnäkin tyyppiryhmä T[]voi sisältää tyypin Tja sen alatyyppien elementtejä .

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

Toiseksi S[]tyyppiryhmä on T[]if: Sn alatyyppi T.

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

On kuitenkin tärkeää muistaa, että: (1) numArrviittaa viitetyyppiin "todellisen tyypin" Number[]"todelliseen objektiin intArr" Integer[].

Siksi seuraava rivi kokoaa hienosti, mutta tuottaa ajonaikaa ArrayStoreException(kasan pilaantumisen vuoksi):

numArr[0] = 1.23; // Not ok

Se tuottaa ajonaikaisen poikkeuksen, koska Java tietää ajon aikana, että "todellinen objekti" intArron itse asiassa matriisi Integer.

Yleiset

Geneeristen tyyppien kohdalla Java-ohjelmalla ei ole tapaa tietää ajon aikana tyypin parametrien tyyppitietoja tyypin poiston takia. Siksi se ei voi suojautua kasan pilaantumiselta ajon aikana.

Sellaiset geneeriset aineet ovat muuttumattomia.

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

Tyyppiparametrien on vastattava tarkasti, jotta voidaan suojata kasan pilaantumiselta.

Mutta kirjoita jokerimerkkejä.

Jokerot, kovarianssi ja ristiriita

Jokerimerkkien avulla geneeriset lääkkeet voivat tukea kovarianssia ja ristiriitaisuutta.

Säätämällä edellistä esimerkkiä saamme tämän, mikä toimii!

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

Kysymysmerkki “?” viittaa yleismerkkiin, joka edustaa tuntematonta tyyppiä. Se voi olla alarajainen, mikä rajoittaa tuntemattoman tyypin olevan tietty tyyppi tai sen supertyyppi.

Siksi rivi 2 ? super Integertarkoittaa "mitä tahansa tyyppiä, joka on kokonaisluku tai sen supertyyppi".

Voit myös käyttää ylärajaa yleismerkissä, joka rajoittaa tuntemattoman tyypin tietylle tyypille tai sen alatyypille ? extends Integer.

Vain luku ja vain kirjoitus

Kovarianssi ja ristiriitaisuus tuottavat mielenkiintoisia tuloksia. Kovariaattityypit ovat vain luku -tilassa, kun taas kiistanalaiset tyypit ovat vain kirjoitettavia.

Muista, että kovariaattityypit hyväksyvät alatyypit, joten 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>.