„Здрасти, Амиго!“
— Здравей, Ели!
„Днес Риши и аз ще ви разкажем всичко за генеричните лекарства.“
— Чакай, мисля, че вече знам почти всичко.
— Почти всичко, но не всичко.
"Наистина ли? Добре, готов съм да слушам."
— Тогава да започваме.
„В Java генериците са класове, които имат параметри на типа.“
„Що се отнася до това защо са измислени генеричните лекарства, вижте коментарите в codeа:“
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
}
Как да решите проблема с помощта на Generics:
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;
}
„Този code просто няма да се компorра и грешката, причинена от добавянето на грешен тип данни, ще бъде забелязана по време на компилацията.“
— Да, вече знам това.
"Добре, добре. Повторението е майката на ученето."
„Но създателите на Java бяха малко мързеливи, когато създаваха генерични файлове. Вместо да създават пълноценни типове с параметри, те се промъкнаха в тънка оптимизация. В действителност те не добавиха ниHowва информация за параметрите на типове към генеричните файлове. Вместо това всички по време на компилация се появява магия."
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);
}
"Това е гладко."
„Да, но този подход има страничен ефект. НиHowва информация за параметрите на типа не се съхранява в общ клас. Този подход по-късно стана известен като изтриване на тип .“
"С други думи, ако имате свой собствен клас с параметри на типа, не можете да използвате информация за тях вътре в класа."
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;
}
}
„По време на компилация всички типове параметри се заменят с Object. И вътре в класа няма информация за типа, който му е предадена.“
— Да, съгласен съм, това не е най-доброто.
"Не е толкова страшно. По-късно ще ви кажа How да заобиколите този проблем."
Но има още. Java ви позволява да посочите родителски тип за параметри на типа. За това се използва ключовата дума extends. Например:
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();
}
}
„Забележете два факта:“
„Първо, не можете да подадете произволен тип като параметър — можете да подадете само Cat or клас, който наследява Cat.“
"Второ, вътре в класа Zoo, променливи от тип T вече могат да извикват методите на класа Cat. Колоната вдясно обяснява защо (защото Cat ще бъде заменен навсякъде, където има T)"
"Да. Ако кажем, че Cat or подклас на Cat се предава като аргумент тип, тогава сме сигурни, че тип T винаги ще има методите на класа Cat."
— Е, това е умно.
GO TO FULL VERSION