#java #performance #generics #bytecode
#java #Производительность #дженерики #байт-код
Вопрос:
Мне интересно, есть ли какая-либо разница во времени выполнения между универсальным контейнером, реализованным с использованием языковых возможностей для дженериков, введенных Java 1.5, по сравнению с выполнением этого только с наследованием и явными приведениями типов. И если есть, что даст наивысшую производительность.
Чтобы быть конкретным, допустим, у меня есть базовый класс и подкласс:
public class Base { }
public class Sub extends Base { }
И я определяю тип контейнера в терминах базового класса. Тогда меня интересует, что происходит, когда известно, что экземпляр контейнера содержит определенный подкласс. До версии 1.5 у меня не было другого выбора, кроме как реализовать контейнер подобным образом (не берите в голову, что это слишком упрощено, чтобы иметь реальный смысл):
public class OldstyleContainer {
private Base x;
public void set(Base x) { this.x = x; }
public Base get() { return x; }
}
И использование класса, в котором известен конкретный тип известного элемента, может выглядеть следующим образом:
public Sub oldstylePut(OldstyleContainer c, Sub s) {
Sub t = (Sub) c.get();
c.set(s);
return t;
}
Теперь, учитывая языковые возможности для дженериков, я бы вместо этого определил контейнер следующим образом:
public class GenericsContainer<T extends Base> {
private T x;
public void set(T x) { this.x = x; }
public T get() { return x; }
}
И соответствующее использование было бы таким:
public Sub genericsPut(GenericsContainer<Sub> c, Sub s) {
Sub t = c.get();
c.set(s);
return t;
}
Код универсальной версии выглядит (очень) немного проще, потому что нет необходимости в явном приведении. Но мой вопрос в том, есть ли какая-либо реальная разница во время выполнения, или это приведение все еще существует в байт-коде? Есть ли еще какая-либо разница?
Комментарии:
1. Скомпилируйте обе версии, затем разберите их с помощью
javap -c
, чтобы увидеть, в чем разница в байт-коде.2. Спасибо за это предложение! Должен был подумать об этом сам. Я сделал это, и они вышли точно такими же, за исключением имен и комментариев. Также пробовал с типом массива в контейнере; тот же результат.
Ответ №1:
Дженерики удаляются — так что к моменту запуска кода компилятор все равно вставил приведения. Вам просто не нужно создавать их самостоятельно в исходном коде при использовании дженериков. Поэтому не учитывайте производительность — используйте дженерики, чтобы сделать код безопаснее.
Ответ №2:
Нет Общей информации, недоступной во время выполнения, это единственная функция во время компиляции.
Универсальные типы реализуются путем удаления типов: информация об универсальном типе присутствует только во время компиляции, после чего она стирается компилятором.