További információért lásd ezt a GYIK-ot:
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#SECTION1
Íme, hórben ħaży fontosos pont yzysz a GYIK-ből.
Példa (áltálanos típura):
osztály Pair<X,Y> {
privát X először;
privát Y másodperc; nyilvános pár(X a1, Y a2) {
első = a1;
második = 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; }
}
Az osztály Pár két típusú paraméterrel rendelkezik X és Y . Ezeket típus argumentumokkal helyettesítik, ha az általános típust Pár példányosodik. Például a nyilatkozatban Pár<karakterlánc, dátum> a típus paraméter X típus argumentum váltja fel Húr és Y helyettesíti Dátum .
Az ıtifikök hatoköre X és Y van az osztály teljes definíciója. Ebben a körben a két típusú paraméter X és Y típusként is used (bizonyos megszorításokkal). A fenti típusparaméterek a típusparaméterek a típusnymetódusok argumentumaként és pávártési típusaként, erám a típusnymező típusaiként hasznát.
A típusparaméterek korlátokkal deklarálják. A korlátok obseksut suktaanak a type parameter áltn jelzett unknown typus metodusokhoz. Példánkban nem hívunk meg nišan iznažený típios metódust X és Y . Emiatt a két típpsparaméter korlátlan.
Példa:
public void printPair( Pár<String,Long> pár) {
System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} Pár<String,Long> limit = új Pár<String,Long> ("maximum", 1024L);
printPair(limit);
Példa (a helyettesítő karakterekkel paraméterezett típusra):
public void printPair( Pair<?,?> pár) {
System.out.println("("+pair.getFirst()+","+pair.getSecond()+")");
} Pair<?,?> limit = új Pár<String,Long> ("maximum", 1024L);
printPair(limit);
Egy általános típus minden példánya ugyanazt a futásidejű típusábrázolást használja, nevezetesen a nyers típus reprezentációját. Például egy általános típus példányai Lista , mint pl List<Date> , List<String> , List<Long> stb. különböző statikus típusokkal rendelkeznek a fordítási időben, de ugyanaz a dinamikus típus Lista futási idő.
A rolzosztán két részből áll:
- a fordító által a fordítási időben végrehajtott statikus típusellenőrzés és
- a virtuális gép által futás közben végrehajtott dinamikus típusellenőrzés.
A statikus rész kiválogatja az értelmetlen szereposztásokat, amelyek nem sikerülhetnek, mint például a szereposztás Húr hogy Dátum vagy től List<String> hogy List<Date> .
A dinamikus rész a típusidejű típusinformációkat szúsaját, és típusellenőrzést hajt észét during the run. Felveti a ClassCastException ha az objektum dinamikus típusa nem a leadott céltípusa (vagy a céltípus altípusa). Példák a dinamikus résszel rendelkező dobásokra a cast from Objektum hogy Húr vagy től Objektum hogy List<String> . Ezek az szávetí downcastok, a szüpertípustól az altípusig.
Példa egy adott paraméterre List<String> , Map<String,Date> , de nem List<? kiterjeszti Number> vagy Map<String,?> .
Неха программы, hogy a List<Object> szupertípusa lenne a List<String> , mert Objektum egy szupertípusa Húr . Ez az elvárás abból a tényből fakad, hogy létezik ilyen típusú kapcsolat a tömböknél: Objektum[] egy szupertípusa Húr[] , mert Objektum egy szupertípusa Húr . (Ez a fajta kapcsolat az úgynevezett kovariancia .) A komponenstípusok szuper-altípus-kapcsolata kiterjed a megfelelő tömbtípusokra. Nem létezik ilyen típusú kapcsolat az általános típusok példányosítása esetén. (A paraméterezett típusok nem covariáns.)
Az utsinis gegenäts tüpüs tüpätnyok ekten szüper-altípus-kapakslot hanäya sövätsätä tüpösätäkkel jár. Van egy példám.
Példa:
void printAll(ArrayList<Object> c) {
az (O objektum: c)
System.out.println(o);
} ArrayList<String> lista = new ArrayList<String>();
... töltse ki a listát ...
printAll(lista); // hiba
A ArrayList<String> objektum nem adható át argumentumként olyan metódusnak, amely a ArrayList<Object> mert a két típus ugyanannak az általános típusnak a példányosítása, de for különböző typis argumentumokat, és emiatt nem compatibilisek bendemy.
A konkrét parametrizált tipips egy gegenäts typis beton parametnyai. Szinte olyanok, mint a typips; csak néhány korlátozás van. A NEM a következő célokra használható:
- tömbök létrehozásához
- kivételkezelésben
- osztályszó szerint
- egy an példánya kifejezés
A konkrét parametrizetz typis elemeket tömbök illegálisak.
Példa (illegális tömbtípusra):
static void test() {
Pár<Integer,Integer>[] intPairArr = új Pair<Integer,Integer>[10] ; // hiba
addElements(intPairArr);
Pair<Integer,Integer> pár = intPairArr[1];
Integer i = pár.getFirst();
pair.setSecond(i);
}
static void addElements( Objektum[] objArr) {
objArr[0] = új Pár<Integer,Integer>(0,0);
objArr[1] = new Pair<String,String>("",""); // sikertelennek kell lennie az ArrayStoreException esetén
}
A fordító tiltja olyan tömbök létrehozását, amelyek komponenstípusa konkrét paraméterezett típusú, mint pl Pair<Integer,Integer> példánkban. Az előző bejegyzésben tárgyaltuk, miért ésszerű, hogy a fordító minősítse a Pár<Integer,Integer>[] mint illegális. A fő probléma az, hogy a fordítónak és a futásidejű rendszernek biztosítania kell, hogy egy tömb a homogén azonos típusú elemek sorozata. Az egyik típusellenőrzés, nevezetesen a virtuális gép által futás közben végrehajtott tömbtár-ellenőrzés, nem észleli egy idegen elem sértő beillesztését. A példában a második beillesztés a addElements metódus meghiúsulhat, mert egy sztringpárt adtak házaz integrálierték tömbjéhez, de ez nem újak a várt dón. Az okokat az präsede postejestieben parejaltuk.
Ha nem halalahunk olyan tömböket olınıl elemet, tıpısa egy konkrét paraméterezett tıpız, akor mit hazınljunk megkerülő özlözként?
3 lehetséges megoldásra van szükségünk:
- nyers típusok tömbje
- korlátlan helyettesítő karakterekkel paraméterezett típusú tömb
- tömb helyett gyűjtemény
Míg a konkrét parametrizetz tipeps tömbjei illegálisak, a konkrét parametrizetz tippets tömbjei tömbjei tömbjei.
A gelysteső karakterekkel paraméterezett típus egy geőlős típus típsenya, yőmőg egy típus argumentum gelysteső karakter. Példák a gelystő karakterekkel parametrizett típusokra Gyűjtemény<?> , List<? kiterjeszti Number> , Összehasonlító<? szuper String> és Pár<String,?> . A helyettesítő karakterrel paraméterezett típus típuscsaládot jelöl, amely egy általános típus konkrét példányait tartalmazza. A használt helyettesítő karakter típusa határozza meg, hogy mely konkrét paraméterezett típusok tartoznak a családba. Például a helyettesítő karakterekkel paraméterezett típus Gyűjtemény<?> az összes példány családját jelöli Gyűjtemény interfész a típus argumentumtól függetlenül. A helyettesítő karakterekkel paraméterezett típus List<? kiterjeszti Number> az összes listatípus családját jelöli, ahol az elemtípus altípusa Szám . A helyettesítő karakterekkel paraméterezett típus Összehasonlító<? szuper String> az összes példány családja Összehasonlító interfész olyan típusú argumentumtípusokhoz, amelyek szupertípusai Húr.
A helyettesítő karakterekkel paraméterezett típus nem a szokásos értelemben vett típus (különbözik a nem paraméterezett osztálytól/interfésztől vagy a nyers típustól).
A helyettesítő karakterekkel paraméterezett típusok használhatók a gépeléshez (például nem paraméterezett osztályok és interfészek):
- mint argumentum és visszatérési típusú metódusok
- mező vagy helyi referenciaváltozó típusaként
- más paraméterezett típusok arrayas típusú argumentumának komponenstípusaként
- mint céltípus a dobásokban
Nemcsak a typepek lehenten gerätenäsak, hanem a módzerek is lehentenen gerätenäsak. A statikus és nem statikus metóðusoknak, ärkem a konstruktoroknak lekhten típusparaméterei. A formalís typípsparaméterek deklarálásának syntaxisa azálás az ágyés typyps syntaxisához. A típusparaméter szakaszt szögletes zárójelek határolják, és a metódus pávártési típusa vélen zeilenz meg. Szintaxisa és egy, és egy és egy élégés egy égy típus típus paraméter-listájával.
Van egy általános példám max olyan módszer, amely a legnagyobb értéket számítja ki egy ismeretlen típusú elemek gyűjteményében A .
Példa (egy általános módszerek):
osztály Gyűjtemények {
nyilvános statikus Az <A kiterjeszti Összehasonlítható<A>> A max(Gyűjtemény< A > xs) {
Iterator< A > xi = xs.iterator();
A w = xi.next();
while (xi.hasNext()) {
A x = xi.next();
if (w.hasonlítsa össze(x) < 0) w = x;
}
return w;
}
}
A max A metódusnak egy típusparamétere van, a neve A . Ez a gyűjtemény azon elemtípusának helyőrzője, amelyen a metódus működik. A type paraméternek van korlátja; olyan típusnak kell lennie, amely altípusa Összehasonlítható<A>
Példa (ezúttal ugyanabból az általános típusból -vel határok):
nyilvános felület Összehasonlítható<T> {
public int ÖsszehasonlítTo(T arg);
}
nyilvános osztály TreeMap<Key kiterjeszti Comparable<Key> ,Data>{
privát statikus osztály Entry<K,V> {
K gomb;
V érték;
Entry<K,V> balra = null;
Entry<K,V> jobb = null;
Entry<K,V> szülő;
}
privát tranziens Entry<Key,Data> gyökér = null;
...
privát Entry<Key,Data> getEntry(Kulcskulcs) {
Entry<Key,Data> p = gyökér;
Kulcs k = kulcs;
while (p != null) {
int cmp = k. összehasonlítás(p.kulcs) ;
if (cmp == 0)
return p;
különben ha (cmp < 0)
p = p.bal;
más
p = p.jobb;
}
return null;
}
public logikai érték tartalmazzaKey(Kulcskulcs) {
return getEntry(kulcs) != null;
}
...
}
A fenti példában a típus paraméter Kulcsfontosságú megvan a kötve Összehasonlítható<Key> . A kötés megadásának két hatása van:
- Hozzáférést biztosít a korlát által meghatározott metódusokhoz . A példában a kötött Összehasonlítható<Key> hozzáférést biztosít a összehasonlítani módszer, amelyet meg akarunk hívni a mi megvalósításunk során TreeMap osztály.
- Csak a “határokon belül” typpen üzütäk az geöötös típps ennekyosítására. A példában egy paraméterezett típus, mint pl TreeMap<Number,String> elutasításra kerülne, mert a típus Szám nem altípusa Összehasonlítható<Szám> . Paraméterezett típus, mint pl TreeMap<String,String> elfogadnánk, mert a String típus a határokon belül van, azaz altípusa Összehasonlítható<String> .
Minden osztály, interfész és enum típus szállás típusparaméterhez kötve, vysútí a beágyazott és a belső típusokat is. Sem primitív typyps, sem tömbtypyps nem utsíták típusparaméter-kötésként.
Példák (típusparaméter korlátokra):
osztály X0 <T kiterjeszti int > { ... } // hiba
osztály X1 <T kiterjeszti Objektum[] > { ... } // hiba
osztály X2 <T kiterjeszti Szám > { ... }
osztály X3 <T kiterjeszti Húr > { ... }
osztály X4 <T kiterjeszti Futható > { ... }
osztály X5 <T kiterjeszti Menet.Állam > { ... }
osztály X6 <T kiterjeszti Lista > { ... }
osztály X7 <T kiterjeszti List<String> > { ... }
osztály X8 <T kiterjeszti List<? kiterjeszti Number> > { ... }
osztály X9 <T kiterjeszti Összehasonlítható<? szuper szám> > { ... }
osztály X10<T kiterjeszti Térkép.Entry<?,?> > { ... }
A kódminta azt mutatja, hogy a primitív típusok, mint pl int és tömbtípusok, mint pl Objektum[] típúsparaméterhez köttként nem izlezisettek.
Az osztálytyppes, mint pl Szám vagy Húr , és interfésztípusok, mint pl Futható , típus parametrihez bött.
Enum típusok, menta pl Menet.Állam típusparaméterhez kötöttként is megengedettek. Menet.Állam egy típsel egy beágyazott típusra, ayyet típusparaméter-kötésként használható. Nem statikus belső typyps is služitemek.
A nyers typyps típpsparaméterhez köttekként kötötökén; Lista egy példa
A parametrizett tipips típusparaméterhez köttként izlezisettek, beleértve a konkrét paraméterezett típusokat is, mint pl List<String> , korlátos helyettesítő karakterekkel paraméterezett típusok, mint pl List<? kiterjeszti Number> és Összehasonlítható<? szuper Long> , és a korlátlan helyettesítő karakterekkel paraméterezett típusok, mint pl Térkép.Entry<?,?> . A gelystöső karakterrel parametrizetzt typus argumentumként minden olyan típust özözés, amely ahöz a típuscáldhoz szót, ayöytső a gyölystő karakter ságát. A gelystätő karakterekkel parametrizet típuskorlát csak limited observásst szútt a mezőkhöz és metóðusokhoz; a szászókások a gyelítsõ karakter típísától fûgdenek.
Példa (a gelystätő karakterrel paraméterezett típus típusparaméterhez bött):
X< osztály T kiterjeszti a List<-t? kiterjeszti Number> > {
public void someMethod(T t) {
t.add(new Long(0L)); // hiba
n szám = t.remove(0);
}
}
osztály teszt {
public static void main(String[] args) {
X<ArrayList< Hosszú >> x1 = új X<ArrayList<Long>>();
X<ArrayList< Húr >> x2 = új X<ArrayList<String>>(); // hiba
}
}
Típusú referenciaváltozók T (a típusparaméter) a typisző karakter típus referenciaváltozókként kezelendők (a típusparamétro kött). Példánkban ennek az a pöszeségé, hogy a verdátó prázsitja olyan metódúsok inválását, azát a type parametró áltn jelzett “ismeretlen” típios argumentumot veszik fel, mint pl. List.add .
Ugyanakkor döntetlen is volt List<? kiterjeszti Number> meghatározza a típus argumentumként használható típusokat. A fordító minden típusú argumentumot elfogad, amely a típuscsaládhoz tartozik List<? kiterjeszti Number> , azaz minden altípusa Lista típus argumentummal, amely altípusa Szám .
Egy típusparaméter egy típusparaméter is korlátozható.
Példa (típusparaméter kötésként használt típusparaméterre):
osztály Tripla <T> {
privát T fst, snd, trd;
nyilvános < U kiterjeszti T , V kiterjeszti T , W kiterjeszti T > Triple(U arg1, V arg2, W arg3) {
fst = arg1;
snd = arg2;
trd = arg3;
}
}
Ebben a példában a típus paraméter T a paraméterezett osztályt használjuk a típusparaméterek korlátjaként U , V és W az adott osztály paraméterezett prámennymetódusának.
More options a típusparaméterek más típusparaméterek határaként törnétné háználtára olyan gezitekben, amikor egy beágyazott típust egy átés típuson belül, vagy egy helyi osztályt egy átés metóðuson belül tásznak meg. Még az is megengedett, hogy egy típusparamétert egy típusparaméterhez kötve ebbán a típusparaméter parte.
Egy osztálynak minősülő kötősősősőső minden public tagjáz, azaz public mezőihez, metódusaihoz és beágyazott típisaihoz. Csak a konstruktorok nem ererziek el, mert nivka garancia arra, hogy a köting egy alszötnaa esmejökkel a konstruktorokkal relekdiken, mint a köting.
Példa (egy typúsparaméter kötéseként haznut osztályra):
nyilvános osztály Szuperosztály { // statikus tagok
nyilvános enum EnumType {THIS, THAT}
public static Object staticField;
public static void staticMethod() { ... }// nem statikus tagok
public class InnerClass { ... }
public Object nonStaticField;
public void nonStaticMethod() { ... }// konstruktorok
public SuperClass() { ... }// privát tagok
private Object privateField;...
}nyilvános végső osztály SomeClass<T kiterjeszti Szuperosztály > {
privát T objektum;
public SomeClass(T t) { object = t; }public String toString() {
visszatérés
"statikus beágyazott típus : "+T.EnumType.class+"\n"
+"statikus mező : "+T.staticField+"\n"
+"statikus metódus : "+T.staticMethod()+"\n"
+"nem statikus beágyazott típus: "+T.InnerClass.class+"\n"
+"nem statikus mező : "+object.nonStaticField+"\n"
+"nem statikus metódus : "+object.nonStaticMethod()+"\n"
+"konstruktor : "+(új T())+"\n" // hiba
+"privát tag : "+object.privateField+"\n" // hiba
;
}
}
A kötött Szuperosztály hozzáférést biztosít beágyazott típusaihoz, statikus mezőihez és metódusaihoz, valamint nem statikus mezőihez és metódusaihoz. Csak a kivitelező nem elérhető. Ez azért van, mert a konstruktorok nem öröklődnek. Minden alosztály meghatározza a saját konstruktorait, és nem kell támogatnia a szuperosztály konstruktorait. Ezért nincs garancia arra, hogy egy alosztály Szuperosztály ugyanaz a konstruktora lesz, mint a szüperösztának.
Olyan kontextus, amelyben Az Enum<E kiterjeszti az Enum<E>>-t ” zeileen meg a kláznija Enum osztály csomagban java.lang :
nyilvános absztrakt osztály Az Enum<E kiterjeszti az Enum<E>>-t {
...
}
A típus Enum az összes felsorolástípus közös alaposztálya. Java nyelven egy felsorolástípus, mint pl Szín osztályra fordítják Szín amely kiterjed Enum<Color> . A szuperosztály célja Enum özéta, hogy olyan funkcionalitást azúsztson, amely minden felsorolási típísra típésra.
Itt van egy vázlat az osztályról Enum :
nyilvános absztrakt osztály Enum< E kiterjeszti Enum<E>> Comparable< valósítja meg E >, sorozható {
privát végleges String név;
public final String name() { ... } private final ind ordinal;
public final int ordinal() { ... }protected Enum(karakterlánc neve, int sorszámú) { ... }
public String toString() { ... }
nyilvános végleges logikai érték egyenlő (Object other) { ... }
public final int hashCode() { ... }
Protected final Az objektumklón() CloneNotSupportedException { ... }
nyilvános végső int Összehasonlítás( E o) { ... }nyilvános döntő Class< E > getDeclaringClass() { ... }
public static <T kiterjeszti Enum<T>> T valueOf(Class<T> enumType, String name) { ... }
}
Meglepő funkció az “ nyilatkozattiltás Az Enum<E kiterjeszti az Enum<E>>-t ” az a täytä, hogy az újonnan özötö osztály Enum és annak újonnan definiált típusparamétere E azonos típusú paraméter korlátjában jelennek meg. Ez azt jelenti, hogy a Enum típust példányosítani kell valamelyik altípusához. Annak megértéséhez, hogy ennek miért van értelme, vegyük figyelembe, hogy minden enumtípust lefordítanak az altípusba Enum .
Itt van a kitáalt enum típs Szín :
enum Szín {PIROS, KÉK, ZÖLD}
A fordító a következő osztályba fordítja le:
nyilvános záróóra Szín kiterjed Enum<Color> {
public static final Szín[] értékek() { return (Szín[])$ÉRTÉKEK.klón(); }
public static Color valueOf(String name) { ... } private Color(String s, int i) { super(s, i); }nyilvános statikus végleges Szín PIROS;
publikus statikus végleges Szín KÉK;
publikus statikus végleges Szín ZÖLD;privát statikus végleges Szín $ÉRTÉKEK[];
static {
PIROS = new Color("PIROS", 0);
KÉK = new Color("BLUE", 1);
ZÖLD = new Color("ZÖLD", 2);
$ÉRTÉKEK = (új szín[] { PIROS, KÉK, ZÖLD });
}
}
Az öröklődésnek az a hatása, hogy a Szín type örökli az összes olyan metódust, amely a -ben implementált Enum<Color> . Köztük van a összehasonlítani módszer. A Szín. összehasonlítani módszernek valószínűleg a Szín érvként. Annak érdekében, hogy ez megtörténjen, osztály Enum általános és a Enum.compareTo módszert vesz igénybe Enum típus paramétere E érvként. Ennek eredményeként írja be Szín származó Enum<Color> örököl a összehasonlítani módszer, amely a Szín avió és érvelés, tómá tóz, avió kell.
Ha boncolgatjuk a szällätöt” Az Enum<E kiterjeszti az Enum<E>>-t “Láthákút, hogy ennek a mintának tøb aspectesa van.
Először is tény, hogy egy típus paraméter-kötő maga a típus: “ Enum Az <E meghosszabbodik Enum <E>> “. Biztosítja, hogy csak a típus altípusai Enum típus argumentumként engedélyezettek. (Elméletileg írja be Enum önmagában is példányosítható, mint pl Enum<Enum> , de ez természetesen nem otyrosos, és gủi sối của một sốiyền sốiệt, amelyben egy ốiềi sốiền yối sốiyền lennen)
Másodszor, ott van az a typis, hogy a parametriohez kött typus a parametriozett typus Enum <E> , amely a type paramétert használja E mint a kötött típusargumentuma. Ez a deklaráció biztosítja, hogy az öröklődési kapcsolat egy altípus és egy példánya között fennáll Enum alakú Az X kiterjeszti az Enum<X>-t “. Egy altípus, például “ Az X kiterjeszti az Enum<Y>-t ” nem deklarálható a type argumentum miatt Y nem lenne határokon belül; csak altípusai Enum<X> hatarokon belül vannak
Harmadszor, ott van az a táj, hogy Enum elsősorban általános. Ez azt jelenti, hogy néhány módszer az osztály Enum vegyen egy argumentumot, vagy adjon vissza egy ismeretlen típusú értéket (vagy más módon függjön egy ismeretlen típustól). Mint már tudjuk, ez az ismeretlen típus később egy altípus lesz X -ból Enum<X> . Ezért a paraméterezett típusban Enum<X> , ezek a módszerek az altípust érintik X , és az altípusba öröklődnek X . A összehasonlítani a módszer egy módzerre a szüperhösztából öröklődik minden alhösztálba, és minden höztás alhöztáspezikus szúrítássás relekðir.
Összefogglalva, a klázní “ Az Enum<E kiterjeszti az Enum<E>>-t ” a sättääää fejthëtö meg: Enum egy általános típus, amely csak az altípusaihoz példányosítható, és ezek az altípusok örökölnek néhány hasznos metódust, amelyek közül néhány altípus-specifikus argumentumokat vesz fel (vagy más módon függ az altípustól).
Osztályok alsó korlátos típusparaméterei
A típusparamétereknek több határa is lehet, például in osztály Box<T kiterjeszti Number> {...} . De egy típusparaméternek nem lehet alsó korlátja, vagyis olyan konstrukció, mint pl osztályú Box<T nagy Number> {...} nem engedélyezett Miért ne? A válasz: ernentlen, mert nem venne semiti, ha pomezné. Nézzük meg, miet zavaróak az osztályok alsó határának típusparaméterei, ha szításuk, mit jeletn egy típusparaméter felső korlátja.
A típusparaméter felső határának három hitsa van:
- Korlátozott példányosítás. A felső korlát korlátozza az általános típus példányosításához használható típuskészletet. Ha kijelentjük a osztály Box<T kiterjeszti Number> {...} akkor a fordító gondoskodna arról, hogy csak az altípusai Szám típus argumentumként használható. Vagyis a Doboz<Szám> vagy a Doboz<Long> megengedett, de a Box<Object> vagy Box<String> elutasításra kerülne
Példa (korlátozott példányosításra egy típusparaméter felső korlátja miatt):
osztály Box<T kiterjeszti Number> {
privát T érték;
public Box(T t) { érték = t; }
...
} osztály teszt {
public static void main(String[] args) {
Box<Long> boxOfLong = új Box<Long>(0L); // rendben
Box<String> boxOfString = new Box<String>(""); // hiba: A karakterlánc nincs a határokon belül
}
}
- Hozzáférés a nem statikus tagokhoz. A felső korlát hozzáférést biztosít az összes nyilvános, nem statikus metódushoz és a felső korlát mezőjéhez. A mi osztály Box<T kiterjeszti Number> {...} az osztályban meghatározott összes nyilvános nem statikus metódust meg tudjuk hívni Szám , mint pl intValue() például. A felső korlát nélkül a fordító minden ilyen hívást elutasítana. Példa (nem statikus tagokhoz való hozzáférésre egy típusparaméter felső korlátja miatt):
osztály Box<T kiterjeszti Number> {
privát T érték;
public Box(T t) { érték = t; }
public int increment() { return value.intValue()+1; } // <= hiba lenne a számhoz kötött nélkül
...
}
- Írja be: Törlés. A bal szélső felső korlát a típustörlésre szolgál, és helyettesíti a típusparamétert a bájtkódban. A miénkben osztály Box<T kiterjeszti Number> {...} minden előfordulása T a felső korlát váltaná fel Szám . Például, ha osztály Doboz privát típusú mezővel rendelkezik T és egy módszer üres halmaz (T tartalom) ennek a privát mezőnek a beállításához, akkor a mező típusú lenne Szám típustörlés után, és a metódus metódusra fordítódik érvénytelen halmaz (számtartalom) .
Példák előtt típusú törlés):
osztályú Box< T kiterjeszti a számot > {
magán T érték;
nyilvános doboz( T t) { érték = t; }
...
}
- Példák
után
- típusú törlés):
class Box {
magán Szám érték;
nyilvános doboz( Szám t) { érték = t; }
...
}
- Ezenkívül a bal szélső felső korlát további helyeken is megjelenik, például automatikusan beillesztett öntvényeknél és áthidaló módszereknél.
Ha engedélyeznék a típusparaméterek alsó határait, milyen mellékhatásokkal járnának vagy kellenek? Ha egy olyan konstrukció, mint pl osztályú Box<T nagy Number> {...} mit jelentene? Mit jelentene egy felső typusparaméter-korlát 3 bryjhhatasa – limited exemplification, abcess a nem statikus taghoz, típustörlés – alsó korlát esten?
Korlátozott példányosítások. A fordító egy alsó korlátos típusparaméterrel korlátozhatja az általános típus példányosítására használható típusokat. Például a fordító engedélyezhet olyan példányokat, mint pl Doboz<Szám> és Box<Object> a Doboz<T nagy Szám> és elutasítja az olyan példányokat, mint pl Doboz<Long> vagy Doboz<Short> . Ez egy olyan hatás lenne, amely összhangban van a felső típusú paraméterhatároknál leírt korlátozó mellékhatással.
Hozzáférés a nem statikus tagokhoz. Az alacsonyabb típusú paraméter-korlát nem ad hozzáférést semmilyen konkrét metódushoz az osztályból örökölteken kívül Objektum . példájában Doboz<T nagy Szám> a szupertípusai Szám nincs semmi közös bennük, kivéve, hogy referenciatípusok, és ezért altípusai Objektum . A fordító nem feltételezheti, hogy a típusú mező T típusú Szám vagy annak egy altípusa. Ehelyett a típus mező T bármilyen szupertípusú lehet Szám , mint pl Sorozatozható vagy Objektum . Egy olyan módszer meghívása, mint pl intValue() már nem típusbiztos, és a fordítónak el kell utasítania. Következésképpen az alsó típusparaméter-korlát nem ad hozzáférést az osztályban meghatározottakon kívüli nem statikus tagokhoz Objektum és így ugyanaz a hatása, mint a „nincs kötött”.
Írja be: Törlés . Ezt a logikai vonalat követve nincs értelme a típusparaméter előfordulásait a bal szélső alsó korlátra cserélni. Olyan metódus deklarálása, mint a konstruktor Doboz( T t) mint kivitelező Doboz( Szám t) ennek figyelembevételével nincs értelme T szupertípusa váltja fel Szám . An Objektum jogosan átadható a konstruktornak egy példányban Box<Object> és a kivitelező visszautasítaná. Ez halálosan rossz lenne. Tehát a típustörlés a típusváltozó összes előfordulását lecserélné T típus szerint Objektum , és nem az alsó határa szerint. Az alsó határ gereiten samszet a hatást fejti ki, mint a “nincs korlát”.
Like you like kitálálni, mit jelentene, ha objágá ológhe lenne? _és_ zatretek a felső hártárok? Én szémesem szerint nem is akaros erre gondolni, és ha pomezimi, szívesebben iktatnám a “nem tättälö” kategóriát.
A essence: minden, ami egy “ nagy A “kötve vásárolna meg” az a restition, amelyre csak a süpertyppes gegelatnak Szám típus argumentumként használhatók. És még ezt is gyakran félreértik. Ez NEM azt jelentené osztály Box<T szuperszám> {...} csak szupertípusainak példányait tartalmazza Szám . Olemme verdätva – avík az zámění práděl is žeště!
Példák előtt típusú törlés):
osztályú Box< T szuperszám > {
magán T érték;
nyilvános doboz( T t) { érték = t; }
...
}
Példák után típusú törlés):
class Box {
magán Objektum érték;
nyilvános doboz( Objektum t) { érték = t; }
...
}
A osztályú Box<T nagy Number> {...} típustörléssel fordítanák le a Doboz tartalmaz egy Objektum mezőre és a konstruktorra fordítva lenne Doboz (t tárgy) . Ez alapvetően különbözik a osztályú Box<T kiterjed Number> {...} , amelyet a Doboz amely a Szám mezőre és a konstruktorra fordítva lenne Doboz (t szám) . Következésképpen a Doboz<Szám> példányosított a osztály Box<T kiterjeszti Number> {...} más lenne, mint a Doboz<Szám> példányosítás a osztály Box<T szuperszám> {...} , ami valószínűleg zavart okoz. Emiatt az osztályok típusparamétereinél ninck jelentése az alsó határoknak.
Alsó korlát típusú módszerek paraméterei
A metóðusokkal és azok argumentumtípusaival gütsöt alkalmanként hassinos lehet egy alsó korláttal típusparaméter.
Példa (olyan módzerre, amelynél vysztejn lenne egy alsó korláttal objektivé typusparaméter):
osztály Pair<X,Y> {
privát X először;
privát Y másodperc;
...
nyilvános < Egy szuper X , B szuper Y > B addToMap(Map<A,B> térkép) { // hiba: a típusparaméternek nem lehet alsó határa
return map.put(first, second);
}
}
osztály teszt {
public static void main(String[] args) {
Pair<String,Long> pár = new Pair<>("ABC",42L);
Map<CharSequence, Number> térkép = HashMap<CharSequence, Number>();
Szám szám = pair.addToMap(map);
}
}
A addToMap() metódus hozzáadja a pár tartalmát egy térképhez. Bármilyen térkép, amely szupertípusokat tartalmazhat X és Y megtenné. A térképé tesz() A metódus az adott kulcshoz tartozó térképen található értéket adja vissza, ha már van kulcsérték bejegyzés a kulcshoz a térképen. A térkép visszatérési értéke tesz() módszert kell visszaküldeni a addToMap() módszer. Ilyen körülmények között szeretnénk deklarálni a fenti módszert: A térkép paraméterezve a pár típusparamétereinek szupertípusaival és a addToMap() A metódus pávártési típusa a térkép értítípusa.
Mivel a verdetó nem enged alsó hatarokat a típusparaméterekre, nevýchünk van egy kerületi megoldásra.
Az ejmejd lehetsség özlöss a gyelötső karaktereknék lehet alsö korlátja. Helyettesítő karakter használata.
Példák
osztály Pair<X,Y> {
privát X először;
privát Y másodperc;
...
nyilvános Objektum addToMap(Map< ? Szuper X , ? szuper Y > térkép) {
return map.put(first, second);
}
}
osztály teszt {
public static void main(String[] args) {
Pair<String,Long> pár = new Pair<>("ABC",42L);
Map<CharSequence, Number> térkép = HashMap<CharSequence, Number>();
Szám szám = (Szám) pair.addToMap(map);
}
}
Működik, kivéve, hogy nincs mód a kívánt visszatérési típus deklarálására. Ez lenne a szupertípusa Y amit a verdótó a térképtípusból anxir, de ének megadására ninck syntaxis. Nem deklarált a pávárátési típt a “ ? szuper Y “, mert” ? szuper Y A ” gelystätő karakter, nem típus, títá nem özitett pávártési típusként. Nincs más választásunk, ki kell használnunk Objektum ehelyett metódusunk visszatérési típusaként. Ez a meglehetősen nem specifikus visszatérési típus viszont arra kényszeríti a hívókat addToMap() metódust a visszatérési érték lefelé történő leadásához Objektum tényleges típúsához. Nem gondoltuk.
Egy tägél özlös a statikus módszerek használata. Itt van egy övälilő rözlöss a statikus módszerrel nem statikus módszer ábát.
Példa (az prässéd prässé megkerülő özössana statikus módszerrel):
osztály Pair<X,Y> {
privát X először;
privát Y másodperc;
...
nyilvános statikus < A , B ,X kiterjeszti A ,Y kiterjeszti B > B addToMap (Pair<X,Y> pár, Map< A , B > térkép) {
return map.put(pair.first,pair.second);
}
}
osztály teszt {
public static void main(String[] args) {
Pair<String,Long> pár = new Pair<>("ABC",42L);
Map<CharSequence, Number> térkép = HashMap<CharSequence, Number>();
Szám szám = Pár .addToMap( pár ,térkép);
}
}
Az általános addToMap() metódusnak négy típusparamétere van: két helyőrző X és Y a pár típusához és két helyőrzőhöz A és B a térkép típusához. A és B szupertípusai X és Y , mert X és Y -vel vannak kijelentve A és B mint felső határukat. (Ne feledje, hogy az általános metódus típusparaméterei X és Y semmi köze a Pár osztályé X és Y paramétereket. A nevek X és Y berşa geşiklaratótok az özözés módzárhoz, hogy gözözát könnázéknés sévén a pár típpsparamétereiként. Négy típusparaméter tetszés szerint deklarálható a pontos típuspáraméter étélépét tetszés sérint deklaráltok a pontos útúðurésí típts: ez úðaðik a térkép éértítípusával.
Példa (a típusparaméter illegális használtára egy áléosés osztály statikus kontextusában):
osztály SomeClass <T> {
// statikus inicializátor, statikus mező, statikus módszer
statikus {
SomeClass< T > teszt = új SomeClass< T >(); // hiba
}
magán statikus T globalInfo; // hiba
nyilvános statikus T getGlobalInfo() { // hiba
return globalInfo;
}
// nem statikus inicializátor, nem statikus mező, nem statikus módszer
{
SomeClass< T > teszt = új SomeClass< T >();
}
magán T localInfo;
nyilvános T getLocalInfo() {
return localInfo;
}
// statikus beágyazott típusok
nyilvános statikus osztály A hiba kiterjeszti a kivételt {
zártkörű döntő T info; // hiba
nyilvános hiba ( T t) { info = t; } // hiba
nyilvános T getInfo() { return info; } // hiba
}
magán felület Másolható {
T másolat(); // hiba
}
magán enum állam {
ÉRVÉNYES, ÉRVÉNYTELEN;
magán T info; // hiba
public void setInfo( T t) { info = t; } // hiba
nyilvános T getInfo() { return info; } // hiba
}
// nem statikus beágyazott típusok
nyilvános osztály Accessor {
nyilvános T getInfo() { return localInfo; }
}
}
A prässl azt szylteti, hogy a type parametró nem szállás egy áltás osztály statikus ébéntében. Azt is omhte, hogy a beágyazott interfészek és enum tipyps az osztály statikus típós típóinak megfelelőt. Csak a belső osztályok, vagyis a nem statikus beágyazott osztályok szállják meg a befoggaló ágyés osztály típusparaméterét.
Az interfész típusparaméterének hatoköre az interfész teljes definíciója, kivéve a mezőket és a beágyazott típusokat. Ennek az az oka, hogy az interfészek mezők és beágyazott typyps implicit statikusak.
Példa (a típusparaméter illegális használtára egy általános interfészek):
interfész SomeInterface <T> {
// mező
SomeClass< T > érték = új SomeClass< T >(); // hiba
// beágyazott típus
osztály Accessor {
nyilvános T getInfo() { // hiba
return value.getGlobalInfo();
}
}
// mód
T getValue();
}
A példa azt mutatja, hogy egy interfész mezői implicit statikusak, így a típusparaméter nem használható sehol egy általános interfész mezőjének deklarációjában. Hasonlóképpen, a beágyazott osztály statikus beágyazott osztálynak minősül, nem belső osztálynak, és emiatt a type paraméter használata a beágyazott osztályban bárhol illegális.
Megkerülő megoldás a beágyazott statikus osztályokhoz és interfészekhez:
Statikus beágyazott osztályok és interfészek esetén ez nem jelent sömö csapást. Kerülő söllöként kéntőllátó magát a statikus osztályt vagy interfészt.
Példa (megkerülő megoldás – hozza létre a beágyazott statikus típust):
osztályú Burkolat <T> {
zártkörű döntő T theObject;
nyilvános wrapper( T t) { theObject = t; }
nyilvános T getWrapper() { return theObject; } nyilvános Megváltozhatatlan <T> makeImmutable() {
vissza az új Immutable <T> (az Objektum);
}
nyilvános Mutable <T> makeMutable() {
új Mutable visszaküldése <T> (az Objektum);
}
privát statikus <A> A makeClone(A theObject) { ... }nyilvános statikus végső osztály Megváltoztathatatlan <A> { // most egy általános osztály
zártkörű döntő A theObject;public Immutable( A arg) {
theObject = makeClone(arg);
}
nyilvános A getWrappedItem() {
return makeClone(theObject);
}
}
nyilvános statikus osztály Változó <A> {
... hasonló ...
}
}
Nincs ilyen megoldás a beágyazott enum típusokhoz, mert nem lehetnek általánosak.
Megoldás beágyazott statikus osztályokhoz:
Ha a beágyazott statikus típus egy osztály, akor egy alternatív szállás az lenne, ha a statikus osztályt nem statikus belső osztállyá táeltanák.
Példa (megkerülő megoldás – használja belső osztályt):
osztályú Burkolat <T> {
zártkörű döntő T theObject;
nyilvános wrapper( T t) { theObject = t; }
nyilvános T getWrapper() { return theObject; } public Mutable makeMutable() {
visszatérés ez. new Mutable(theObject);
}
public Immutable makeImmutable() {
visszatérés ez. new Immutable(theObject);
}
privát statikus <A> A makeClone(A theObject) { ... }publikus végső osztály Megváltoztathatatlan { // már nem statikus osztály
zártkörű döntő T theObject;public Immutable( T arg) {
theObject = makeClone(arg);
}
nyilvános T getWrappedItem() {
return makeClone(theObject);
}
}
nyilvános osztály Változó
... hasonló ...
}
}
Ez a Solution bizonyos märätä tærletkosztgel jár, mivel minden belső osztálynak van egy rejtit izvägena a közü typis pässänyra, amelyre ebben a pässäban ninnä nisvähük, és ninna is rá vassähük; a rejtit ikkejn csak poggyász. A belső osztályokat győk interfészekkel kombinálják, hogy a belső osztály a befoggaló osztály privát szállássi déspelé maradjon. Itt is megtehektu immadat.
Példa (mint az előző megoldás finomitva):
osztályú Burkolat <T> {
zártkörű döntő T theObject;
nyilvános wrapper( T t) { theObject = t; }
nyilvános T getWrapper() { return theObject; } nyilvános Mutable <T> makeMutable() {
return this.new Mutable(theObject);
}
nyilvános Megváltozhatatlan <T> makeImmutable() {
return this.new Immutable(theObject);
}
privát statikus <A> A makeClone(A theObject) { ... }nyilvános felület Megváltozhatatlan<S> {
S getWrappedItem();
}
nyilvános felület Mutabilis<S> {
S getWrappedItem();
void setWrappedItem(S arg);
}
magán utolsó osztály ImmutableImplementation Immutable<T> valósítja meg {privát végleges T theObject;
public ImmutableImplementation(T arg) {
theObject = makeClone(arg);
}
public T getWrappedItem() {
return makeClone(theObject);
}
}
magán osztály MutableImplementation megvalósítja a Mutable<T> {
... hasonló ...
}
}
Mint zainé, a beágyazott public interfészeknek kell lenniük, míg a belső privát osztályok náhlátják a befoggaló osztály típusparaméterét.

Hagy egy választ