– Szia Amigo!
– Szia, Ellie!
"Ma Rishi és én mindent elmondunk a generikus gyógyszerekről."
– Várj, azt hiszem, már szinte mindent tudok.
– Majdnem mindent, de nem mindent.
"Tényleg? Oké, kész vagyok meghallgatni."
– Akkor kezdjük.
"A Java-ban az általánosok olyan osztályok, amelyek típusparaméterekkel rendelkeznek."
"Ami azt illeti, hogy miért találták ki a generikus gyógyszereket, lásd a kód megjegyzéseit:"
ArrayList stringList = new ArrayList();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // Add a number to the list
for(Object o: stringList)
{
String s = (String) o; // There will be an exception here when we get to the integer
}
A probléma megoldása a Generics használatával:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("abc"); // Add a string to the list
stringList.add("abc"); // Add a string to the list
stringList.add( 1 ); // There will be a compilation error here
for(Object o: stringList)
{
String s = (String) o;
}
"Ez a kód egyszerűen nem fordítható le, és a fordítás során észreveszik a rossz adattípus hozzáadása okozta hibát."
– Igen, ezt már tudom.
"Rendben, jó. Az ismétlés a tanulás anyja."
"A Java készítői azonban egy kicsit lusták voltak, amikor generikusokat készítettek. Ahelyett, hogy teljes értékű típusokat készítettek volna paraméterekkel, belecsúsztak egy sima optimalizálásba. A valóságban nem adtak hozzá semmilyen információt a típusparaméterekről a generikusokhoz. Ehelyett az összes varázslat fordul elő az összeállítás során."
List<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("abc");
strings.add( 1); // Compilation error
for(String s: strings)
{
System.out.println(s);
}
List strings = new ArrayList();
strings.add((String)"abc");
strings.add((String)"abc");
strings.add((String) 1); // Compilation error
for(String s: strings)
{
System.out.println(s);
}
– Ez sima.
"Igen, de ennek a megközelítésnek van egy mellékhatása. A típusparaméterekről semmilyen információ nem tárolódik egy általános osztályon belül. Ez a megközelítés később típustörlés néven vált ismertté ."
"Más szóval, ha van saját osztályod típusparaméterekkel, akkor az osztályon belül nem használhatsz rájuk vonatkozó információkat."
class Zoo<T>
{
ArrayList<T> pets = new ArrayList<T>();
public T createAnimal()
{
T animal = new T();
pets.add(animal)
return animal;
}
}
class Zoo
{
ArrayList pets = new ArrayList();
public Object createAnimal()
{
Object animal = new ???();
pets.add(animal)
return animal;
}
}
"A fordítás során minden paramétertípust lecserélnek Object-re. Az osztályon belül pedig nincs információ a neki átadott típusról."
– Igen, egyetértek, ez nem a legjobb.
"Nem olyan ijesztő. Később elmondom, hogyan lehet megkerülni ezt a problémát."
De van több is. A Java segítségével megadhat szülőtípust a típusparaméterekhez. Erre az extends kulcsszót használjuk. Például:
class Zoo<T extends Cat>
{
T cat;
T getCat()
{
return cat;
}
void setCat (T cat)
{
this.cat = cat;
}
String getCatName()
{
return this.cat.getName();
}
}
class Zoo
{
Cat cat;
Cat getCat()
{
return cat;
}
void setCat(Cat cat)
{
this.cat = cat;
}
String getCatName()
{
return this.cat.getName();
}
}
"Jegyezz meg két tényt:"
"Először is, nem adhatsz át akármilyen típust paraméterként – csak egy macskát vagy egy olyan osztályt adhatsz át, amely örökli a Cat-et."
"Másodszor, az Állatkert osztályon belül a T típusú változók mostantól hívhatják a Cat osztály metódusait. A jobb oldali oszlop megmagyarázza, hogy miért (mert a Cat mindenhol, ahol T van, fel lesz cserélve)"
"Igen. Ha azt mondjuk, hogy a Cat vagy a Cat egy alosztálya típus argumentumként kerül átadásra, akkor biztosak vagyunk benne, hogy a T típusban mindig a Cat osztály metódusai lesznek."
– Hát, ez okos.
GO TO FULL VERSION