Įvadas į bendrinius „Java“ tipus: kovariacija ir prieštaringumas

Tipai

„Java“ yra statiškai įvesta kalba, o tai reiškia, kad prieš naudodami pirmiausia turite deklaruoti kintamąjį ir jo tipą.

Pavyzdžiui: int myInteger = 42;

Įveskite bendrinius tipus.

Bendrieji tipai

Apibrėžimas: „ Bendrasis tipas yra bendroji klasė arba sąsaja, kuri parametruojama pagal tipus.“

Iš esmės bendrieji tipai leidžia jums parašyti bendrą, bendrinę klasę (arba metodą), kuri veikia su skirtingais tipais, leidžianti pakartotinai naudoti kodą.

Užuot nurodę, objkad yra inttipo, Stringtipo ar bet kokio kito tipo, jūs apibrėžiate Boxklasę, kad priimtumėte tipo parametrą <; Tada galite nnaudoti T, kad atstovautumėte tam bendriniam tipui bet kurioje jūsų klasės dalyje.

Dabar įveskite kovaranciją ir prieštaringumą.

Kovarsija ir prieštaringumas

Apibrėžimas

„Dispersija“ nurodo, kaip subtiliavimas tarp sudėtingesnių tipų yra susijęs su subtipais tarp jų komponentų (šaltinio).

Lengvai įsimenamas (ir neformalus) kovariacijos ir prieštaringumo apibrėžimas:

  • Kovariacija: priimkite potipius
  • Kontraversija: priimkite supertipus

Masyvai

„Java“ masyvai yra nevienodi , o tai turi 2 implikacijas.

Pirma, tipo masyve T[]gali būti tipo Tir jo potipių elementai.

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

Antra, tipo masyvas S[]yra „ T[]if S“ potipis T.

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

Tačiau svarbu atsiminti, kad: (1) numArryra nuoroda į „tikrojo tipo“ Number[]„faktinį objektą intArrInteger[].

Todėl ši eilutė sudarys puikų rezultatą, tačiau sukurs vykdymo laiką ArrayStoreException(dėl krūvos taršos):

numArr[0] = 1.23; // Not ok

Tai sukuria vykdymo laiko išimtį, nes „Java“ vykdymo metu žino, kad „tikrasis objektas“ intArriš tikrųjų yra masyvas Integer.

Generikai

Taikant bendruosius tipus, „Java“ neturi galimybės vykdymo metu žinoti tipo parametrų informacijos dėl tipo ištrynimo. Todėl ji negali apsaugoti nuo krūvos taršos vykdymo metu.

Taigi generiniai vaistai yra nekintami.

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

Tipo parametrai turi tiksliai atitikti, kad būtų apsaugota nuo krūvos taršos.

Bet įveskite pakaitos simbolius.

Pakaitos simboliai, kovariacija ir prieštaringumas

Naudodami pakaitos simbolius, generikai gali palaikyti kovariaciją ir prieštaringumą.

Patikslinus ankstesnį pavyzdį, gauname tai, kas veikia!

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

Klausiamasis ženklas „?“ reiškia pakaitos simbolį, kuris reiškia nežinomą tipą. Jis gali būti apatinės ribos, o tai riboja nežinomą tipą kaip konkretų tipą ar jo supertipą.

Todėl 2 eilutėje ? super Integerišverstas į „bet kokį tipą, kuris yra sveikasis skaičius arba jo supertipas“.

Taip pat galite naudoti viršutinę pakaitos simbolį, kuris apriboja nežinomą tipą kaip konkretų tipą ar jo potipį ? extends Integer.

Tik skaityti ir tik rašyti

Kovariacija ir prieštaringumas duoda įdomių rezultatų. Kovariantiniai tipai yra tik skaitomi, o kontravariantiniai - tik rašomieji.

Atminkite, kad kovariantiniai tipai priima potipius, taigi 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>.