Witaj Amigo!
- Cześć, Ellie!
— Dzisiaj Risha i ja opowiemy wam wszystko o lekach generycznych.
„Więc w pewnym sensie wiem już prawie wszystko.
Prawie wszystkie, ale nie wszystkie.
- Tak? Dobra, jestem gotowy do słuchania.
– W takim razie zaczynajmy.
Typy generyczne w Javie to klasy zawierające typy parametrów.
Powody pojawienia się generycznych - patrz komentarz w kodzie:
ArrayList stringList = new ArrayList();
stringList.add("abc"); //добавляем строку в список
stringList.add("abc"); //добавляем строку в список
stringList.add( 1 ); //добавляем число в список
for(Object o: stringList)
{
String s = (String) o; //тут будет исключение, когда дойдем до element-числа
}
Jak leki generyczne rozwiązują problem:
ArrayList<String> stringList = new ArrayList<String>();
stringList.add("abc"); //добавляем строку в список
stringList.add("abc"); //добавляем строку в список
stringList.add( 1 ); //тут будет ошибка компиляции
for(Object o: stringList)
{
String s = (String) o;
}
Taki kod po prostu się nie skompiluje, a błąd z dodaniem danych złego typu zostanie zauważony na etapie kompilacji.
"Już to wiem.
- To wspaniale. Powtarzanie jest matką nauki.
Ale programiści Java trochę pomieszali podczas tworzenia Generic i zamiast tworzyć pełnoprawne typy z parametrami, schrzanili sprytną optymalizację. W rzeczywistości do typów nie dodano żadnych informacji o ich typach parametrów, a cała magia wydarzyła się na etapie kompilacji.
List<String> strings = new ArrayList<String>();
strings.add("abc");
strings.add("abc");
strings.add( 1); // тут ошибка компиляции
for(String s: strings)
{
System.out.println(s);
}
List strings = new ArrayList();
strings.add((String)"abc");
strings.add((String)"abc");
strings.add((String) 1); //ошибка компиляции
for(String s: strings)
{
System.out.println(s);
}
- Hitro, tak.
Tak, ale takie podejście ma efekt uboczny. Wewnątrz klasy ogólnej nie są przechowywane żadne informacje o typie jej parametru. To podejście zostało później nazwane wymazywaniem czcionek.
Te. jeśli masz własną klasę z typami parametrów, nie możesz używać informacji o nich wewnątrz klasy.
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;
}
}
Podczas kompilacji wszystkie typy parametrów są zastępowane przez Object. I nie ma informacji o typie, który został mu przekazany w klasie.
Tak, zgadzam się, to nie jest zbyt dobre.
- Dobra, to nie takie straszne, później ci opowiem, jak nauczyli się obejść ten problem.
Ale to nie wszystko. Java umożliwia określenie typu nadrzędnego dla typów parametrów. W tym celu używane jest słowo kluczowe extends. Przykład:
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();
}
}
Zwróć uwagę na dwa fakty.
Po pierwsze, możliwe jest teraz przekazanie nie dowolnego typu jako typu parametru, ale typu Cat lub jednego z jego potomków.
Po drugie, w klasie Zoo zmienne typu T mogą teraz wywoływać metody klasy Cat. Dlaczego - wyjaśniono w kolumnie po prawej stronie (ponieważ typ T zostanie wszędzie zastąpiony typem Cat)
- Tak. Jeśli powiedzieliśmy, że typ Cat lub jego potomkowie są przekazywani jako parametr typu, to jesteśmy pewni, że typ T musi mieć metody klasy Cat.
Dobrze. Sprytny.
GO TO FULL VERSION