FakiNyan написав:я от шарп наче знаю, але дженерики ніколи не юзав. Якось побачив код знайомого, щось типу
void Method<T>(T obj)
{
if(T==typeof(int))
{
}
else if(T==typeof(float))
{
}
}
ну щось типу таке, і думаю - а нафіг воно мені тре? я можу просто перевантажити метод під необхідні типи аргументів, і все буде те ж саме і без купи if'ів
Перед тим як запитати "а нафіг воно треба", запитайте себе "а чи розробники майже усіх типізованих мов, імплементували б таку, не найпростішу, функціональність у своїх мовах просто так?" А відповідь на це питання треба шукати у книжках і документації, а не у кривому коді знайомих
Покажу приклад "нафіг".
Уявіть завдання: заімплементувати клас ArrayList списку на основі масиву. Клас має бути генеричним у тому сенсі, що 1 його імплементація може використовуватися для переховування різних типів значень, хоч і одного(!!!) типу.
Імплементація без дженеріків (java):
class ArrayList {
private Object[] body;
public void add(Object value) {
// add value to this.body
}
public Object get(int index) {
return body[index];
}
}
А тепер про мінуси такої реалізації:
1) Необхідне зведення типів. Якщо навіть у вас ліст містить лише Integer, то усе одно вам треба зводити типи, бо get повертає Object:
ArrayList list = new ArrayList();
list.add(15);
int firstElement = (Integer) list.get(0);
2) Невизначеність фактичного типу зберігаємих елементів. Іншими словами, так як у нас імплементація на основі масиву Object[], ми можемо у нього пхати що завгодно і те, що там лежить, відомо лише під час runtime.
ArrayList list = new ArrayList();
list.add(15); // OK
list.add(new Home()); // теж ОК
list.add("asdadada"); // теж ОК
І під час list.get() ви насправді не знаєте який там тип і з'являються бридкі конструкції на кшталт:
Object rawElement = list.get(0);
if (rawElement instanceof String) {
//
} else if (rawElement instanceof Integer) {
//
}
+ якщо слідкувати вимозі, що ліст може містити лише дані 1 типу, треба робити перевірки під час add(). До того ж треба визначити яким саме чином визначати той головний тип з яким порівнювати, під час тієї перевірки (на приклад передавати у конструктор клас new ArrayList(Integer.class) і з ним у add перевіряти)
Імплементація з дженеріками (java):
class ArrayList<T> {
private T[] body;
public void add(T value) {
// add value to this.body
}
public T get(int index) {
return body[index];
}
}
Такий код виправляє всі проблеми попереднього підходу:
1) Тип визначений під час компіляції та ним й перевіряється. Використовуючи такий код, ви самостійно вказуєте тип і тим самим змушуєте компілятор перевіряти типи що там знаходяться.
ArrayList<Integer> list = new ArrayList<>();
list.add(15); // OK
list.add(new Home()); // compile time error, Home is NOT instanceof Integer
list.add("asdadada"); // compile time error, String is NOT instanceof Integer
Жодних перевірок instanceof.
2) Так як тип визначений під час компіляції, жодних додаткових зведень не вимагається.
ArrayList<Integer> list = new ArrayList();
list.add(15);
int firstElement = list.get(0); // компілятор вже на цій стадії знає що там лише int