Разница в производительности в универсальных типах Java по сравнению со старинными дженериками?

#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:

Нет Общей информации, недоступной во время выполнения, это единственная функция во время компиляции.

Универсальные типы реализуются путем удаления типов: информация об универсальном типе присутствует только во время компиляции, после чего она стирается компилятором.