Відповіді:
Ну, мотивація (зворотна сумісність) є і перевагою, і недоліком. Це є недоліком, оскільки всі ми вважаємо за краще мати повторювані типи, але ціна, яку потрібно платити, була високою. Розглянемо вибір дизайну в C #. Вони мають повторювані типи, але тепер у них є копії API. Отже, уявіть Java API, де ми також мали дублікати API для кожного параметризованого класу. Тепер уявіть себе, як переносите тисячі рядків коду зі застарілих класів у нові загальні класи. Тепер хто б не вважав дублікати API недоліком? Але ей, вони мають повторювані типи!
Отже, головною мотивацією була "еволюція, а не революція". І логічно, що кожне рішення має компроміси.
Окрім інших згаданих недоліків, ми також можемо додати той факт, що стирання типу може бути важко пояснити під час компіляції, оскільки не очевидно, що певні типи будуть видалені, а це призводить до дуже дивних і важко знайти помилок.
Існування мостових методів (цей синтаксично сформований метод компілятора для збереження бінарної сумісності) також може розглядатися як недолік. І це може бути саме однією з причин помилок, про які я згадував у попередньому пункті.
Основні недоліки випливають із уже очевидного факту, що існує один клас, а не декілька класів для родових типів. В якості іншого прикладу розглянемо, що перевантаження методу з тим же загальним класом у Java не вдається:
public void doSomething(List<One>);
public void doSomething(List<Two>);
Щось можна вважати недоліком типів, що повторюються (принаймні в C #), - це те, що вони викликають вибух коду . Наприклад, List<int>це один клас, а List<double>інший зовсім інший, як це List<string>і є List<MyType>. Тому класи повинні визначатися під час виконання, спричиняючи вибух класів та витрачаючи цінні ресурси під час їх генерування.
Щодо того, що неможливо визначити асиміляцію на new T()Java, згадану в іншій відповіді, також цікаво врахувати, що це не лише питання стирання типу. Він також вимагає існування конструктора за замовчуванням, тому C # вимагає для цього "нового обмеження". (Дивіться, чому новий T () не можливий на Java , автор Алекс Баклі).
Мінусом стирання типу є те, що ви не знаєте під час виконання типу загального типу. Це означає, що ви не можете застосувати до них роздуми і не можете їх створити під час виконання.
На Java не можна зробити щось подібне:
public class MyClass<T> {
private T t;
//more methods
public void myMethod() {
//more code
if (someCondition) {
t = new T();//illegal
} else {
T[] array = new T[];//illegal
}
}
}
Для цього існує вирішення, але для цього потрібно більше коду. Перевага, як ви вже згадували, - зворотна сумісність.
Ще одна перевага стираних дженериків полягає в тому, що різні мови, що компілюються в JVM, використовують різні стратегії генерики, наприклад, сайт визначення Scala порівняно з коваріацією сайту використання Java. Крім того, більш високі типи дженериків Scala було б складніше підтримувати в рефікованих типах .Net, тому що фактично Scala on .Net ігнорував несумісний формат редагування C #. Якби ми реіфікували дженерики в JVM, швидше за все, ці модифіковані дженерики не були б придатними для функцій, які нам справді подобаються у Scala, і ми б застрягли в чомусь неоптимальному. Цитуючи з блогу Ола Біні ,
Це все означає, що якщо ви хочете додати в JVM рефіковані дженерики, ви повинні бути впевнені, що ця реалізація може охоплювати як всі статичні мови, які хочуть зробити інновації у власній версії дженериків, так і всі динамічні мови, які хочуть створити хорошу реалізацію та приємний інтерфейс із бібліотеками Java. Тому що якщо ви додасте доопрацьовані дженерики, які не відповідають цим критеріям, ви пом'якшите інновації та зробите це набагато складніше використовувати JVM як багатомовну віртуальну машину.
Особисто я не вважаю необхідність використання TypeTagконтексту, пов'язаного в Scala, для конфліктних перевантажених методів як недолік, оскільки це переміщує накладні та негнучкість переробки від глобальної (ціла програма та всі можливі мови) на сайт використання на кожній мові питання, яке трапляється лише рідше.
Ts, ви отримуєте лише одну копіюClass<T>коду для всіхTs; плюс додаткова копія для кожного використовуваного типу значенняT.