Lai iegūtu papildinformāciju, lūdzu, skatiet šo FAQ:
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#SECTION1
Šeit ir daži svarīgi punkti šajā FAQ.
Piemēri (vispārējs skats):
klase Pair<X,Y> {
privātais X vispirms;
privātais Y sekunde; publiskais pāris(X a1, Y a2) {
pirmais = a1;
otrais = a2;
}
public X getFirst() { return first; }
public Y getSecond() { return second; }
public void setFirst(X arg) { first = arg; }
public void setSecond(Y arg) { second = arg; }
}
Klase Pāris ir divu veidu parametri X un Y . Tie tiek aizstāti ar tipa argumentiem, ja ir vispārīgs veids Pāris ir momentāni. Piemēram, deklarācijā Pāris<String, Datums> tipa parametrs X tiek aizstāts ar tipa argumentu Stīga un Y tiek aizstāts ar Datums .
Identifikatoru sikke joma X un Y ir visa klases definīcija. Šajā jomā divu veidu parametri X un Y tiek veidi kā tie (ar ar sikkem veidu veidi). The fent minēts piemērā tipa parametri are used as instances metožu arguments un atkrzijas veids un katu lauku veidi.
Tipa parametrus var deklarēt ar rožām. Robežas nodrošina piekļuvi nezināma tipa methodes, kuras apzīmē tipa parametrus. Mūsu piemērā mēs neizsaucam nejras nezīnāmu yūtu metodes X un Y . Tāpēc abi tipa parametri nav ierobežoti.
Piemēri (konkrēta tipa parametriem):
public void printPair( Pāris<String, Long> pāris) {
System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} Pāris<String, Long> limits = jauns Pāris<String, Long> ("maksimums", 1024L);
printPair(limit);
Piemērs (aizstājējzīmes parametrizētam tipam):
public void printPair( Pair<?,?> pāris) {
System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} Pair<?,?> limits = jauns Pāris<String, Long> ("maksimums", 1024L);
printPair(limit);
Visām vispārīgā tipa instancēm ir viens un tas pats izpildlaika tipa attēlojums, proti, neapstrādātā tipa attēlojums. Piemēram, vispārēja veida instancijas Saraksts , piemēram, Saraksts<Datums> , Saraksts<String> , Saraksts<Long> uc ir dažādi statiskie tipi kompilēšanas laikā, bet viens un tas pats dinamiskais tips Saraksts கிற்றுல்லிக்கு
Aktieris sastāv no divām daļām:
- statiskā tipa pārbaude, ko kompilators veic kompilēšanas laikā un
- dinamiska tipa pārbaude, ko izpildes laikā veic virtuālā mašīna.
Statiskā daļa izšķir nejēdzīgus metienus, kas nevar izdoties, piemēram, cast no Stīga ka Datums vai no Saraksts<String> ka Saraksts<Datums> .
Dinamiskā daļia zaļu ķištārlaika tipa informācija un uzdīšana veiļa veic tipa veriļi. Tas paaugstina a ClassCastException ja objekta dinamiskais tips nav cast mērķa tips (vai mērķa tipa apakštips). Metienu piemēri ar dinamisko daļu ir cast no Objekts ka Stīga vai no Objekts ka Saraksts<String> . Tie ir tā kukatie downcasts, saktu no supertipa tīlā sākt.
Konkrētu parametrizētu tipu ir Saraksts<String> , Karte<String,Datums> , bet ne List<? pagarina Number> vai Map<String,?> .
Dažreiz tiek szättäts, ka a Saraksts<Object> būtu supertips a Saraksts<String> , jo Objekts ir supertips Stīga . Šīs cerības izriet no fakta, ka masīviem pastāv šāda veida attiecības: Objekts[] ir supertips virkne[] , jo Objekts ir supertips Stīga . (Šāda veida attiecības ir pazīstamas kā kovariācija .) Komponentu tipu super-apakštipu attiecības izvēršas līdz atbilstošajiem masīvu veidiem. Šāda veida attiecības nepastāv vispārīgu tipu instancēm. (Parametru veidi ir nē kovarianti.)
Super-apakštipu riņu ľiņoštam starp vienu un tā paša geļeļīgā tipa instancēm ir vispusīgas sekas. Šeit ir piemērs.
Piemēri:
void printAll(ArrayList<Object> c) {
priekš (Objekts : c)
System.out.println(o);
} ArrayList<String> saraksts = new ArrayList<String>();
... aizpildīt sarakstu ...
drukātVisu(saraksts); // kļūda
A ArrayList<String> objektu nevar nodot kā argumentu metodei, kas prasa a ArrayList<Object> jo abi veidi ir viena un tā paša vispārīgā tipa instancijas, bet priekš dažādi tipa argumentus, un šī otura dūl tie nav savietojami viens ar otru.
Betona parametrizizetie tipi ir vispārīgs konkrētu gadījumu veids. Tie ir kässä sämälä tipiem; ir tikaki kadın sındırım. Tos NEKAD neizmantojiet šādiem mērķiem:
- masīvu izveidošanai
- izņēmumu apstrādē
- klases burtiski
- in an instanceof izteiksme
Masīvi, kuros ir elementi, kuru tips ir konkrēti parametrizēts tips, ir nelegāli.
Piemēri (nelegāla masīva tipa):
static void test() {
Pāris<Vesels skaitlis, Vesels skaitlis>[] intPairArr = jauns Pāris<Vesels skaitlis, Vesels skaitlis>[10] ; // kļūda
addElements(intPairArr);
Pāris<Integer,Integer> pāris = intPairArr[1];
Vesels skaitlis i = pāris.getFirst();
pair.setSecond(i);
}
static Void addElements( Objekts[] objArr) {
objArr[0] = jauns Pāris<Vesels skaitlis, Vesels skaitlis>(0,0);
objArr[1] = jauns pāris<String,String>("",""); // vajadzētu neizdoties ar ArrayStoreException
}
Kompilators aizliedz izveidot masīvus, kuru komponenta tips ir konkrēts parametrizēts tips, piemēram Pāris<Integer,Integer> mūsu piemērā. Iepriekšējā ierakstā mēs apspriedām, kāpēc ir saprātīgi, ka kompilators kvalificē a Pāris<Vesels skaitlis, Vesels skaitlis>[] kā nelikumīgu. Galvenā problēma ir tā, ka kompilatoram un izpildlaika sistēmai ir jānodrošina, lai masīvs būtu a viendabīgs viena veida elementu secība. Viena no veida pārbaudēm, proti, masīva veikala pārbaude, ko veic virtuālā mašīna izpildlaikā, neizdodas atklāt sveša elementa aizskarošu ievietošanu. Piemērā otrais ievietojums addElements metodei pārān neizdoties, jo vīmēn pūdīja virkņu pāri integralālo vaṃtu masīvam, dān tā neizdodas, kā sīmātā. Iemesli tika apspriests iepriekšējā ierakstā.
Ja mēs nevaram osmūt masīvus, kas satur elēmenas, kuru tips ir konkrēts parametrizēts tips, ko mēms sūtram kā sēļus?
Mēs apsveram 3 iespējamos risinājumus:
- neapstrādātu veidu klāsts
- neierobežota aizstājējzīmju parametrizēta tipa masīvs
- kolekcija masīva vietā
Lai gan betona parametru tipu masīvi ir ilāmīti, betona parametru tipu kolekcija ir authtatas.
Aizstājējzīme parametrizētais tips ir generala tipa instānē, kur māk viens tipa argumenti ir aiztājējzīme. Aizstājējzīmu parametrīzēto tipu irāmīmī ir Kolekcija<?> , List<? pagarina Number> , Comparator<? super String> un Pair<String,?> . Aizstājējzīmes parametrizētais tips apzīmē tipu saimi, kas ietver konkrētas vispārēja tipa instancijas. Izmantotās aizstājējzīmes veids nosaka, kuri konkrētie parametrizētie veidi pieder saimei. Piemēram, aizstājējzīmes parametrizētais tips Kolekcija<?> apzīmē visu instantiāciju saimi Kolekcija interfeiss neatkarīgi no argumenta tipa. Aizstājējzīmes parametrizētais tips List<? pagarina Number> apzīmē visu sarakstu tipu saimi, kur elementa tips ir apakštips Numurs . Aizstājējzīmes parametrizētais tips Comparator<? super String> ir visu instanču saime Salīdzinātājs saskarne tipa argumentu tipiem, kas ir supertipi Stīga.
Aizstājējzīmes parametrizētais tips nav tips parastajā nozīmē (atšķiras no neparametrizētas klases/saskarnes vai neapstrādāta tipa).
Rakstīšanai var izmantot aizstājējzīmju parametrizētos tipus (piemēram, klases un saskarnes bez parametriem):
- kā argumentu un atgriešanas veidu metodes
- kā lauka vai vietējā atsauces mainīgā veids
- kā citu parametrizētu tipu masīva tipa argumenta komponenta tips
- kā mērķa veids metienos
Ne tikai veidi var būt geļorniņi, bet arī metodes var būt geĆornijas. Statiskām un nestatikām metodiam, kā arī konstruktoriem var būt tipa parametri. Formālo tipu parametru deklarēšanas sintakse ir aluana generalo tipu sintaksei. Tipa parametra izjaja ir norobežota ar leņķa iekavām un zažije prīne metodes atkržežas veida. Tā sintakse un tejna ir identitāte spējīgā tipa tipa parametru sarakstam.
Šeit ir piemērs maks metode, kas aprēķina lielāko vērtību nezināma veida elementu kolekcijā A .
Piemēri (vispārējai metodei):
klases kolekcijas {
publiska statiska <A pagarina Salīdzināms<A>> A max (Kolekcija< A > xs) {
Iterators< A > xi = xs.iterator();
A w = xi.next();
while (xi.hasNext()) {
A x = xi.next();
ja (w.salīdzinātTo(x) < 0) w = x;
}
atgriezties w;
}
}
The maks metodei ir viens tipa parametrs, nosaukts A . Tas ir vietas turētājs kolekcijas elementa tipam, kurā darbojas metode. Tipa parametram ir ierobežojums; tam ir jābūt veidam, kas ir apakštips Salīdzināms<A>
Piemērs (šoreiz tā paša vispārīgā tipa ar robežas):
publiska saskarne Salīdzināms<T> {
publisks int salīdzinātTo(T arg);
}
publiskā klase TreeMap<Key pagarina Salīdzināms<Key> ,Data>{
privātā statiskā klase Entry<K,V> {
K taustiņš;
V vērtība;
Entry<K,V> pa kreisi = null;
Entry<K,V> pa labi = null;
Entry<K,V> vecāks;
}
privāts pārejošs Entry<Key,Data> sakne = null;
...
privātā ievade<Key,Data> getEntry (atslēgas atslēga) {
Entry<Key,Data> p = sakne;
Taustiņš k = atslēga;
while (p != null) {
int cmp = k. salīdzinātTo(p.key) ;
ja (cmp == 0)
atgriezties p;
citādi, ja (cmp < 0)
p = p.pa kreisi;
cits
p = p.pa labi;
}
return null;
}
publiskais Būla satursKey(Key key) {
atgriezties getEntry(atslēga) != null;
}
...
}
Iepriekš minētajā piemērā tipa parametrs Atslēga ir saistīts Salīdzināms<Key> . Iesiešanas specifikācijai ir divas sekas:
- Tas nodrošina piekļuvi metodēm, kuras nosaka saite . Piemērā iesiets Salīdzināms<Key> nodrošina piekļuvi salīdzināt Ar metode, kuru mēs vēlamies izmantot, īstenojot mūsu TreeMap klasē.
- Vispārāgā tipa instantiāciāti var āsutāt tikai tipus “ierobežās”. Piemērā parametrizēts tips, piemēram, TreeMap<Number,String> tiktu noraidīts, jo tips Numurs nav apakštips Salīdzināms<Number> . Tāds parametrizēts tips kā TreeMap<String,String> tiktu pieņemts, jo tips String ir robežās, t.i., ir apakštips Salīdzināms<String> .
Visas klases, saskarnes un enum tipus var ausutt kā tipa parametru ossitus, til gejdjotos un internos tipus. Ne primitīvi tipi, ne masīvu veidi are not used kā tipa parametru saistība.
Piemēri (tipa parametrs rožām):
klase X0 <T pagarina starpt > { ... } // kļūda
klase X1 <T pagarina Objekts[] > { ... } // kļūda
klase X2 <T pagarina Numurs > { ... }
klase X3 <T pagarina Stīga > { ... }
klase X4 <T pagarina Palaist > { ... }
klase X5 <T pagarina Pavediens.Valsts > { ... }
klase X6 <T pagarina Saraksts > { ... }
klase X7 <T pagarina Saraksts<String> > { ... }
klase X8 <T pagarina List<? pagarina Number> > { ... }
klase X9 <T pagarina Salīdzināms<? super numurs> > { ... }
klase X10<T pagarina Karte.Entry<?,?> > { ... }
Koda paraugs parāda, ka primitīvie veidi, piemēram, starpt un masīvu veidi, piemēram, Objekts[] nav aututti kā tipa parametri.
Klases veidi, piemēram Numurs vai Stīga , un saskarnes veidi, piemēram, Palaist , ir aututti kā tipa parametri.
Enum veidi, piemēram Pavediens.Valsts ir atļauti arī kā tipa parametri. Pavediens.Valsts ir ġiġjotā tipa ġiġġi, kas tiek ġiġi kā tipa parametru ġiġijums. Ir austret ar nonstatsiki veidrisnie veidi.
Neaptäläfti tipi ir autätti kä tipa parametrum sämäti; Saraksts un piemērs.
Parametru tipi ir aututti kā tipa parametri, tostarp specifiski parametrizēti veidi, piem. Saraksts<String> , ierobežoti aizstājējzīmes parametrizētie tipi, piemēram, List<? pagarina Number> un Salīdzināms<? super Long> , un neierobežoti aizstājējzīmju parametrizētie veidi, piemēram, Karte.Entry<?,?> . Iesaistījums, kas ir azizitējzīme parametrizīts tips, kā tipa arguments līgīt sūtām visus sīmus, kas piðar tipu saimei, ko denoti azizitējzīme. Aizstājējzīmes parametrizā tipa saistība tīki uzrebegotu uzksiļu laukiem un metodēm; ierobežojumi ir veida no azizitējzīme veida.
Piemēri
klase X< T pagarina List<? pagarina Number> > {
public void someMethod(T t) {
t.add(new Long(0L)); // kļūda
Skaitlis n = t.remove(0);
}
}
klases ieskaite {
public static void main(String[] args) {
X<ArrayList< Garš >> x1 = jauns X<ArrayList<Long>>();
X<ArrayList< Stīga >> x2 = jauns X<ArrayList<String>>(); // kļūda
}
}
Tipa atsauces mainīgie T (tipa parametrs) tiek obsukti kā azizitējzīmes tipa avāzēs mainīgie (tipa parametrs ir vysutų). Mūsu piemērā sekas ir takas, ka kompilators noraida tāju metožu izsaukšanu, kas zakuji “nezināma” tipa argumentu, ko apzīmē tipa parametrus, piem. List.add .
Tāpēc tas ir saistošs List<? pagarina Number> nosaka veidus, kurus var izmantot kā tipa argumentus. Kompilators pieņem visus tipa argumentus, kas pieder tipu saimei List<? pagarina Number> , tas ir, visi apakštipi Saraksts ar tipa argumentu, kas ir apakštips Numurs .
Tipa parametra var ausutt kā cita tipa parametra saiti.
Piemēr (tipa parametram, ko zakuji kā tipa parametara saktivi):
klase Trīskāršs <T> {
privātais T fst, snd, trd;
publiskais < U pagarina T , V pagarina T , W pagarina T > Triple(U arg1, V arg2, W arg3) {
fst = arg1;
snd = arg2;
trd = arg3;
}
}
Šajā piemērā tipa parametrs T no parametrizētās klases tiek izmantota kā tipa parametru saistība U , V un W šīs klases parametrizētās gadījumu metodes.
Citas sättätsätätä tipa parametrus kä citu tipa parametre säätätä ätätä äätäsätä, kad gässäts tips ir definitën gässätsīgā tipa vai locale klase ir definitsana gäbbessīgā metodē. Ir pat aututts austut tipa parametri kā cita tipa parametra sādatām tāh pasām tipa parametri saksūtu.
Iesaistījums, kas ir klase, nodrošina piekļuvi visiem publiskajiem dalībniekiem, tas ir, public laukiem, metodīm un uzjdsotajiem dinādiem. Tikai konstruktori nav pieejami, jo nav garantija, ka saites abçklasei ir tädi pashi konstruktori kä saitei.
Piemēr (klasei, ko zakai kā tipa parametrs saiti):
publiska klase Superklase { // statiski dalībnieki
publiskais saraksts EnumType {THIS, THAT}
public static Object staticField;
public static void staticMethod() { ... }// nestatiski dalībnieki
publiska klase InnerClass { ... }
publiskais objekts nonStaticField;
public void nonStaticMethod() { ... }// konstruktori
publiska SuperClass() { ... }// privātie dalībnieki
private Object privateField;...
}publiskā fināla klase SomeClass<T pagarina Superklase > {
privātais T objekts;
public SomeClass(T t) { objekts = t; }public String toString() {
atgriezties
"static ligzdota tips : "+T.EnumType.class+"\n"
+"statiskais lauks : "+T.staticField+"\n"
+"statiskā metode : "+T.staticMethod()+"\n"
+"nestatisks ligzdots veids: "+T.InnerClass.class+"\n"
+"nestatisks lauks : "+object.nonStaticField+"\n"
+"nestatiskā metode : "+object.nonStaticMethod()+"\n"
+"konstruktors : "+(jauns T())+"\n" // kļūda
+"privāts dalībnieks : "+object.privateField+"\n" // kļūda
;
}
}
Saistīts Superklase nodrošina piekļuvi tā ligzdotajiem veidiem, statiskajiem laukiem un metodēm, kā arī nestatiskajiem laukiem un metodēm. Tikai konstruktors nav pieejams. Tas ir tāpēc, ka konstruktori netiek mantoti. Katra apakšklase definē savus konstruktorus, un tai nav jāatbalsta savas virsklases konstruktori. Tādējādi nav garantijas, ka apakšklase Superklase būs takk pats konstruktors kā tās superklasei.
Kontteksts, kura Enum<E paplašina Enum<E>> Parādās deklarācija Enum klase iepakojumā java.lang :
publiska abstraktā klase Enum<E paplašina Enum<E>> {
...
}
Veids Enum ir visu uzskaitīšanas veidu kopējā bāzes klase. Java valodā uzskaites veids, piemēram, Krāsa tiek tulkots klasē Krāsa kas pagarina Enum<Color> . Superklases mērķis Enum ir svett funktionalität, kas ir sämma viesom sävätätääs svetät.
Šeit ir klases skice Enum :
publiska abstraktā klase Enum< E pagarina Enum<E>> ievieš Comparable< E >, serializējams {
privāts beigu virknes nosaukums;
publiskais gala virknes nosaukums() { ... } privāts gala ind ordināls;
public final int ordinal() { ... }Protected Enum (virknes nosaukums, int kārtas) { ... }
public String toString() { ... }
publiska galīgā Būla vērtība ir vienāda (Object other) { ... }
public final int hashCode() { ... }
aizsargāts gala Objekta klons() izmet CloneNotSupportedException { ... }
publisks gala int salīdzinātTo( E o) {...}publiskais fināls Class< E > getDeclaringClass() { ... }
publiskais statiskais <T paplašina Enum<T>> T valueOf(Class<T> enumType, virknes nosaukums) { ... }
}
Pārsteidzoša iezīme deklarācijā “ Enum<E paplašina Enum<E>> ” ir fakts, ka jaunizveidotā klase Enum un tā jaundefinētais tipa parametrs E parādās tā paša tipa parametra robežās. Tas nozīmē, ka Enum tips ir jāveido vienam no tā apakštipiem. Lai saprastu, kāpēc tas ir jēga, ņemiet vērā, ka katrs enum veids tiek tulkots apakštipā Enum .
Šeit ir dažas idejas Krāsa :
enum Krāsa {SARKANS, ZILS, ZAĻS}
Kompilators to pārtulko šādā klasē:
publiskā noslēguma klase Krāsa pagarina Enum<Color> {
public static final Color[] value() { return (Color[])$VALUES.clone(); }
public static Color valueOf(virknes nosaukums) { ... } privātā Krāsa(String s, int i) { super(s, i); }publiska statiska gala Krāsa SARKANA;
publiska statiskā fināla Krāsa ZILA;
publiska statiskā gala Krāsa ZAĻA;privāts statisks gala Krāsa $VALUES[];
static {
SARKANS = jauna krāsa ("SARKANS", 0);
ZILS = new Color("ZILS", 1);
ZAĻS = jauna krāsa ("ZAĻA", 2);
$VĒRTĪBAS = (jauna krāsa[] { SARKANS, ZILS, ZAĻS });
}
}
Mantojumam ir tāda ietekme, ka Krāsa tips manto visas tajā ieviestās metodes Enum<Color> . Starp tiem ir salīdzināt Ar metodi. The Krāsa. salīdzināt Ar metodei, iespējams, vajadzētu ņemt a Krāsa kā arguments. Lai tas notiktu klase Enum ir vispārīgs un Enum.compareTo metode aizņem Enum tipa parametrs E kā arguments. Rezultātā ierakstiet Krāsa atvasināts no Enum<Color> manto a salīdzināt Ar metode, kas prasa a Krāsa kā un argumenti, kā tā, kā bār.
Ja mēs sadalām deklarāciju “ Enum<E paplašina Enum<E>> “Mēs redzam, ka šim modelim ir vairāki aspekti.
First, ir fakts, ka tipa parametru saistība ir pats tips: “ Enum <E pagarina Enum <E>> “. Tas sözütü, ka tiki tipa apçtipi Enum ir atļauti kā tipa argumenti. (Teorētiski ierakstiet Enum varētu būt iemiesojumā pats par sevi, piemēram, in Enum<Enum> )
Otrkārt, ir fakts, ka ar parametrı vesıntais tips ir parametrizertais tips Enum <E> , kas izmanto tipa parametru E kā saistījuma tipa arguments. Šī deklarācija nodrošina mantojuma attiecību starp apakštipu un instantiāciju Enum ir formas X paplašina Enum<X> “. Apakštips, piemēram, “ X paplašina Enum<Y> ” nevar deklarēt tipa argumentu dāl Y nebūtu robežās; tikai apakštipi Enum<X> ir rožās.
Treškärt, ir fakts, ka Enum pirmkārt, ir vispārīgs. Tas nozīmē, ka dažas no klases metodēm Enum ņemt argumentu vai atgriezt nezināma tipa vērtību (vai citādi būt atkarīga no nezināma veida). Kā mēs jau zinām, šis nezināmais tips vēlāk būs apakštips X no Enum<X> . Tādējādi parametrizētajā tipā Enum<X> , šīs metodes ietver apakštipu X , un tie tiek mantoti apakštipā X . The salīdzināt Ar methode ir säkees metodes piemērs; tas tiek mants no virsklases in every subclass, un in every subclass tam ir subclassei specific paraksts.
Rezumējot, deklarācija “ Enum<E paplašina Enum<E>> ” var atshifrēt šādi: Enum ir vispārīgs tips, ko var iemiesot tikai tā apakštipiem, un šie apakštipi pārmantos dažas noderīgas metodes, no kurām dažas izmanto apakštipam specifiskus argumentus (vai citādi ir atkarīgi no apakštipa).
Klašu apakšējās robežas tipa parametri
Tipa parametriem var būt vairākas robežas, piemēram, in klases Box<T pagarina Number> {...} . Bet tipa parametram nevar būt zemākas robežas, tas ir, tāda konstrukcija kā klases Box<T lieliski Numurs> {...} nav atļauts. Kāpēc ne? Atbilde ir: tas ir bezjēdzīgi, jo tas jums neko nepirktu, ja tas būtu tātutāt. Redzēsim, kišu klašu začejnej sznejnej tipa parametri ir mulsinoši, ko sznejnej klašu žejnejne rojeza tipa parametri ir mulsinoši, ko sznečije tipa parametri zajnejne rojeza.
Tipa parametra za sverai rozhai ir trės efekti:
- Ierobežota instancē. Augšējā robeža ierobežo veidu kopu, ko var izmantot vispārīgā tipa instancēm. Ja mēs pasludinām a klases Box<T pagarina Number> {...} tad kompilators nodrošinātu, ka tikai apakštipi Numurs var izmantot kā tipa argumentu. Tas ir, a Kaste<Number> vai a Kaste<Long> ir atļauts, bet a Box<Object> vai Box<String> tiktu noraidīts
Piemērs (ierobežotai instantiācijai tipa parametra augšējās robežas dēļ):
klases Box<T pagarina Number> {
privātā T vērtība;
publiskā kaste(T t) { vērtība = t; }
...
} klases ieskaite {
public static void main(String[] args) {
Box<Long> boxOfLong = jauns Box<Long>(0L); // labi
Box<String> boxOfString = jauns Box<String>(""); // kļūda: virkne nav robežās
}
}
- Piekļuve nestatiskajiem dalībniekiem. Augšējā robeža nodrošina piekļuvi visām publiskajām nestatiskajām metodēm un augšējās robežas laukiem. Īstenojot mūsu klases Box<T pagarina Number> {...} mēs varam izsaukt visas klasē definētās publiskās nestatiskās metodes Numurs , piemēram, intValue() piemēram. Bez augšējās robežas kompilators noraidītu jebkuru šādu izsaukšanu. Piemērs (piekļuve nestatiskiem dalībniekiem tipa parametra augšējās robežas dēļ):
klases Box<T pagarina Number> {
privātā T vērtība;
publiskā kaste(T t) { vērtība = t; }
public int increment() { return value.intValue()+1; } // <= būtu kļūda, ja numurs nebūtu saistīts
...
}
- Ierakstiet Dzēst. Kreisākā augšējā robeža tiek izmantota tipa dzēšanai, un tā aizstāj tipa parametru baita kodā. Mūsu klases Box<T pagarina Number> {...} visi gadījumi T tiktu aizstāta ar augšējo robežu Numurs . Piemēram, ja klase Kaste ir privāts tipa lauks T un metode tukšs komplekts (T saturs) lai iestatītu šo privāto lauku, lauks būtu tipa Numurs pēc tipa dzēšanas un metode tiks pārtulkota par metodi nederīgs komplekts (skaita saturs) .
Piemēri (parametra augšējās lietošanas robežas veids un dzēšanas gadījuma veids – pirms tam veida dzēšana):
klases Box< T paplašina Skaitli > {
privāts T vērtība;
publiskā kaste( T t) {vērtība = t; }
...
}
- Piemēri (parametra augšējās lietošanas robežas veids un dzēšanas gadījuma veids –
pēc
- veida dzēšana):
class Box {
privāts Numurs vērtība;
publiskā kaste( Numurs t) {vērtība = t; }
...
}
- Turklāt tālākās kreisās malas augšējā robeža parādās citās vietās, piemēram, automātiski ievietotos metienos un tilta metodēs.
Ja tipa parametriem būtu atļautas zemākas robežas, kādas blakusparādības tām būtu vai tām vajadzētu būt? Ja tāda konstrukcija kā klases Box<T lieliski Numurs> {...} bija atļauts, ko tas nozīmētu? Ko augšējā tipa parametru ierobežojuma 3 blakusefekti — ierobežota instanču izveide, piekļuve nestatiskajam dalībniekam, tipa dzēšana — nozīmētu apakšējai robežai?
Ierobežotas instancijas. Kompilators var ierobežot tipu kopu, ko var izmantot vispārīgā tipa instancēm ar zemākas robežas tipa parametru. Piemēram, kompilators varētu atļaut tādas instancijas kā Kaste<Number> un Box<Object> no a Kaste<T lieliski Numurs> un noraidīt instancijas, piemēram, Kaste<Long> vai Kaste<Short> . Tas būtu efekts, kas atbilstu ierobežojošajam blakusefektam, kas aprakstīts augšējā tipa parametru robežām.
Piekļuve nestatiskajiem dalībniekiem. Zemāka tipa parametru robeža nedod piekļuvi nevienai konkrētai metodei, izņemot tās, kas mantotas no klases Objekts . Piemērā Kaste<T lieliski Numurs> supertipi Numurs tiem nav nekā kopīga, izņemot to, ka tie ir atsauces tipi un līdz ar to apakštipi Objekts . Kompilators nevar pieņemt, ka lauka tipa T ir tipa Numurs vai tā apakštips. Tā vietā tipa lauks T var būt jebkura supertipa Numurs , piemēram, Serializējams vai Objekts . Tādas metodes piesaukšana kā intValue() vairs nav tipa drošs, un kompilatoram tas būtu jānoraida. Rezultātā zemākā tipa parametru robeža nedotu piekļuvi nestatiskiem elementiem, kas pārsniedz klasē definētos Objekts un tämää tam ir takk pats efekts kä “bez konsiminiem”.
Ierakstiet Dzēst . Ievērojot šo loģikas līniju, nav jēgas tipa parametra gadījumus aizstāt ar tā vistālāk kreiso apakšējo robežu. Metodes deklarēšana, piemēram, konstruktors Box( T t) kā konstruktors Box( Numurs t) nav jēgas, ņemot vērā to T tiek aizstāts ar supertipu Numurs . An Objekts var pamatoti nodot konstruktoram instantiācijā Box<Object> un konstruktors to noraidītu. Tas būtu ļoti nepareizi. Tātad tipa dzēšana aizstātu visus tipa mainīgā gadījumus T pēc veida Objekts . Atkal kešerajai rozai būtu tāja pati indētā kā “bez kepejuma”.
Vēlaties uzzināt, ko tas nozīmē, ja abi būtu ķemēri _un_ augšējās robežas bija atļautas? Personīgi es pat nevēlos par to muttīt un, ja attīlijāt, labprātāk to inscriptu tupului “nav pārādāms”.
Apakšējā līnia ir: viss, kas ir “ lieliski ” Saistīts būtu nopirkt jums ir kepējums, ka tikai supertypes Numurs var izmantot kā tipa argumentus. Un pat tas bieži tiek pārprasts. Tas NEBŪTU to nozīmēt klases Box<T supernumurs> {...} satur tikai supertipu gadījumus Numurs . Gluži důvůdi – kā pierāda zemāk kilatais piemērs!
Piemēri (parametra augšējās lietošanas robežas veids un dzēšanas gadījuma veids – pirms tam veida dzēšana):
klases Box< T supernumurs > {
privāts T vērtība;
publiskā kaste( T t) {vērtība = t; }
...
}
Piemēri (parametra augšējās lietošanas robežas veids un dzēšanas gadījuma veids – pēc veida dzēšana):
class Box {
privāts Objekts vērtība;
publiskā kaste( Objekts t) {vērtība = t; }
...
}
A klases Box<T lieliski Numurs> {...} tiktu tulkots pēc tipa dzēšanas uz a Kaste satur an Objekts lauks un tā konstruktors tiktu tulkots uz Kaste (objekts t) . Tas būtiski atšķiras no a klases Box<T pagarina Numurs> {...} , kas tiktu tulkots kā a Kaste kas satur a Numurs lauks un tā konstruktors tiktu tulkots uz Kaste (numurs t) . Līdz ar to a Kaste<Number> iemiesots no a klases Box<T pagarina Number> {...} atšķirtos no a Kaste<Number> instantiācija no a klases Box<T supernumurs> {...} . Tas ir iemesls, kāpēc maksimālie ierobežojumi ir vienādi.
Metožu apakšējās robežas tipa parametri
Saistībā ar metodikas un to argumentu dināmā dažkārt var būt utilisā tipa parametri ar apākējo rožu.
Piemēri
klase Pair<X,Y> {
privātais X vispirms;
privātais Y sekunde;
...
publiskais < Super X , B super Y > B addToMap(Map<A,B> karte) { // kļūda: tipa parametram nevar būt apakšējā robeža
atgriezties karte.put(pirmais, otrais);
}
}
klases ieskaite {
public static void main(String[] args) {
Pāris<String,Long> pāris = jauns Pāris<>("ABC",42L);
Map<CharSequence, Number> karte = HashMap<CharSequence, Number>();
Skaitļa numurs = pair.addToMap(map);
}
}
The addToMap() metode pievieno pāra saturu kartei. Jebkura karte, kurā var būt supertipi X un Y darītu. Kartes likt () metode atgriež kartē atrasto vērtību dotajai atslēgai, ja atslēgai kartē jau ir atslēgas vērtības ieraksts. Kartes atgriešanas vērtība likt () metode tiek atgriezta no addToMap() metodi. Šādos apstākļos metodi vēlamies deklarēt, kā parādīts iepriekš: Karte ir parametrizēta ar pāra tipa parametru supertipiem un addToMap() metodes atkrzijas veids ir kartes valerjes padomi.
Tā kā kompilatori nepieļauj zemākus parametrus, mums ir nepieciešams risinājums.
Viens no odszīmēm, kas nāk sāmām, ir aziztējzīmem izmāti, jo aziztējzīmēm var būt gešera roža. Šis ir risinājums, izmantojot azizitējzīmi.
Piemēri
klase Pair<X,Y> {
privātais X vispirms;
privātais Y sekunde;
...
publiski Objekts addToMap (Map< ? Super X , ? super Y > karte) {
atgriezties karte.put(pirmais, otrais);
}
}
klases ieskaite {
public static void main(String[] args) {
Pāris<String,Long> pāris = jauns Pāris<>("ABC",42L);
Map<CharSequence, Number> karte = HashMap<CharSequence, Number>();
Skaitļa numurs = (Numurs) pair.addToMap(karte);
}
}
Tas darbojas, izņemot to, ka nav iespējams deklarēt atgriešanas veidu kā vēlamo. Tas būtu supertips Y ko kompilators tver no kartes veida, bet nav sintakses tā lietošanai. Mēs negribam deklarēt atkržeže vyšu “ ? super Y “, jo” ? super Y ” ir azistējzīme, nevis veids, un söre tas nav auttats kā atkržežes veids. Mums nav kombes, un tas ir sikkem Objekts tā vietā kā mūsu metodes atgriešanas veids. Šis diezgan nespecifiskais atgriešanas veids savukārt liek zvanīt uz addToMap() metodi, lai samazinātu atgriešanās vērtību no Objekts til tā aktualjam veidam. Tieši par to mēs runājām.
Vēl viens risinājums ir statistikas metožu izmantošana. Šeit ir risinājums, izmantojot statiskas metodes, nevis statiskas metodes.
Piemēr (iepriekšējā piemēra risinājumām, izmantojot statisku metodi):
klase Pair<X,Y> {
privātais X vispirms;
privātais Y sekunde;
...
publiski statisks < A , B ,X pagarina A ,Y pagarina B > B addToMap (pāris<X, Y> pāris, Map< A , B > karte) {
atgriešanās karte.put(pair.first,pair.otrais);
}
}
klases ieskaite {
public static void main(String[] args) {
Pāris<String,Long> pāris = jauns Pāris<>("ABC",42L);
Map<CharSequence, Number> karte = HashMap<CharSequence, Number>();
Skaitļa numurs = Pāris .addToMap( pāri ,karte);
}
}
Vispārīgais addToMap() metodei ir četri tipa parametri: divi vietturi X un Y pāra tipam un diviem vietturiem A un B kartes veidam. A un B ir supertipi X un Y , jo X un Y ir deklarēti ar A un B kā to augšējās robežas. (Ņemiet vērā, ka vispārīgās metodes tipa parametri X un Y nav nekāda sakara ar Pāris klases X un Y parametrus. Vārdi X un Y tiek atkārtoti izmantotas vispārīgās metodes, lai saratu tos viegli velignajumus kā pāra tipa parametrus. Izmantojot četru veidu parametrus, mēs varam deklarēt precīzus reklāmguvumus, ko vēlamies veikt:
Piemēri (tipa parametra nelegāli izmantikai vispārējās klases statiskā kontekstā):
klase SomeClass <T> {
// statiskais inicializators, statiskais lauks, statiskā metode
statisks {
SomeClass< T > tests = jauns SomeClass< T >(); // kļūda
}
privāts statisks T globalInfo; // kļūda
publiski statisks T getGlobalInfo() { // kļūda
atgriezt globalInfo;
}
// nestatiskais inicializators, nestatiskais lauks, nestatiskā metode
{
SomeClass< T > tests = jauns SomeClass< T >();
}
privāts T LocalInfo;
publiski T getLocalInfo() {
atgriezt vietējo informāciju;
}
// statiski ligzdotie veidi
publiski statisks klasē Kļūme pagarina izņēmumu {
privātais fināls T informācija; // kļūda
publiska neveiksme ( T t) { info = t; } // kļūda
publiski T getInfo() { atgriešanās informācija; } // kļūda
}
privāts saskarne Kopējams {
T kopēt (); // kļūda
}
privāts enum štats {
DERĪGS, NEDERĪGS;
privāts T informācija; // kļūda
public void setInfo( T t) { info = t; } // kļūda
publiski T getInfo() { atgriešanās informācija; } // kļūda
}
// nestatiskie ligzdotie veidi
publiski klasē Piekļuve {
publiski T getInfo() { return localInfo; }
}
}
Piemērā pēstātā, ka tipa parametri nevar osvātā general class static context. Tas arı déset, ka yjëdjotās saskarnes un enum tipi tiek besetani par klases statica tipa säskarnes. Tikai intsiras klases, tas ir, nonestatikas jajdjotās klases, var austāt tētūrōsās geļbērātās klāses tipa parametru.
Interfeisa tipa parametre sikke joma ir visa saskarnes definīcija, izņemot visus laukus vai yjdjotos vayus. Tas ir sämä, ka saskarnē definitienie lauki un gejdjotie veidi ir induktiki statiski.
Piemēr (nelegāla tipa parametra sāskarnē)
interfeiss SomeInterface <T> {
// lauks
SomeClass< T > vērtība = jauns SomeClass< T >(); // kļūda
// ligzdots veids
klasē Piekļuve {
publiski T getInfo() { // kļūda
atgriež vērtību.getGlobalInfo();
}
}
// metodes
T getValue();
}
Piemērā parādīts, ka saskarnes lauki ir netieši statiski, tāpēc tipa parametru nevar izmantot nekur vispārīgas saskarnes lauka deklarācijā. Tāpat ligzdotā klase tiek uzskatīta par statisku ligzdotu klasi, nevis iekšējo klasi, un šī iemesla dēļ tipa parametra izmantošana jebkur ligzdotajā klasē ir nelikumīga.
Risinājums ligzdotām statiskām klasēm un saskarnēm:
Statisku ġiġotu klašu un saskarņu ġaġi tā nav liela nešemene. Kā sātu mēs varam Ķenerēt pashu statisko klasi vai saskarni.
Piemēri
klases Iesaiņotājs <T> {
privātais fināls T objekts;
publiskais iesaiņotājs( T t) {Objekts = t; }
publiski T getWrapper() { return theObject; } publisks Nemainīgs <T> makeImmutable() {
atgriezt jaunu Immutable <T> (Objekts);
}
publisks Mainīgs <T> makeMutable() {
atgriezt jaunu Mutable <T> (Objekts);
}
privāts statisks <A> A makeClone(A theObject) { ... }publiska statiskā beigu klase Nemainīgs <A> { // tagad ir vispārīga klase
privātais fināls A objekts;publisks nemainīgs( A arg) {
theObject = makeClone(arg);
}
publiski A getWrappedItem() {
atgriezt makeClone(Objekts);
}
}
publiska statiskā klase Mainīgs <A> {
... līdzīgi...
}
}
Nav šāda risinājuma ligzdotajiem uzskaites veidiem, jo tie nevar būt vispārīgi.
Risinājums ligzdotām statiskām klasēm:
Ja jajjotais statiskais veids ir klase, alternativs solution botu statiskas klases präzijana par nestatikau sisteno klasi.
Piemēr (risinājums - izmantot iekšējo klasi):
klases Iesaiņotājs <T> {
privātais fināls T objekts;
publiskais iesaiņotājs( T t) {Objekts = t; }
publiski T getWrapper() { return theObject; } public Mutable makeMutable() {
atgriezties šis. jauns Mutable(Objekts);
}
public Immutable makeImmutable() {
atgriezties šis. jauns Nemainīgs(Objekts);
}
privāts statisks <A> A makeClone(A theObject) { ... }publiska gala klase Nemaināms { // vairs nav statiska klase
privātais fināls T objekts;publisks nemainīgs( T arg) {
theObject = makeClone(arg);
}
publiski T getWrappedItem() {
atgriezt makeClone(Objekts);
}
}
publiskā klase Mainīgs
... līdzīgi...
}
}
This solution ir vysutų ar kīmānām kāsīms, jo visām intīrām klasēm ir āskita āzūtē uz eksītā tipa instanci, kas seiņi piemērā tām nav drāja un teīdī utilitā; askatā reference ir tiki bagāža. Lielākā daļa iekšējo klašu ir apvienotas ar saskarnēm, lai saglabātu iekšējo klasi privātās ieviešanas detaļās. Mes varam doret to pashu seit.
Piemēri (ti, iepriekšējais risinājums un uzlabots):
klases Iesaiņotājs <T> {
privātais fināls T objekts;
publiskais iesaiņotājs( T t) {Objekts = t; }
publiski T getWrapper() { return theObject; } publisks Mainīgs <T> makeMutable() {
return this.new Mutable(theObject);
}
publisks Nemainīgs <T> makeImmutable() {
return this.new Immutable(theObject);
}
privāts statisks <A> A makeClone(A theObject) { ... }publiskais interfeiss Nemaināms<S> {
S getWrappedItem();
}
publiskais interfeiss Mutable<S> {
S getWrappedItem();
void setWrappedItem(S arg);
}
privāts beigu klase NemaināmaIeviešana ievieš Immutable<T> {privāts fināls T theObject;
public ImmutableImplementation(T arg) {
theObject = makeClone(arg);
}
public T getWrappedItem() {
atgriezt makeClone(Objekts);
}
}
privāts klase MutableImplementation ievieš Mutable<T> {
... līdzīgi...
}
}
As you can see, the nested publiskajām saskarnēm ir kūbīga ģeļeļīmāgīms, tārātās sūtras privātās klāses var āsūtās sāskarnēm publiskajām saskarnēm ir kābībā gītāsīgīms, tārātās privātās klāses var sātātām sāskarnēm sāskarnēm.

Atstājiet atbildi