3-й семестр / Лекции / 6 - Презентация 2 - Дженерики, Абстрактные типы данных, Стек
.pdfЦентр дистанционного обучения
Generics
Объявление “class AnyList<E>” – это объявление “заготовки” типа, а конкретный тип AnyList<Integer> устанавливает параметр E=Integer. Поэтому метод get для AnyList<Integer>
возвращает тип Integer.
Синтаксически это похоже на C++ templates, но реализовано по-другому, что имеет последствия при использовании generics в программах.
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Пример:
public class AnyBox<E> { private E value = null;
public E get() { return value; }
public void set(E newValue) { value = newValue; }
}
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
public class AnyBox<E> { private E value = null; public E get() {
return value;
}
public void set(E newValue) {
value = newValue;
}
}
AnyBox<String> box = new AnyBox<>();
box.set(“Some string”);
String boxValue = box.get();
public class AnyBox {
private Object value = null; public Object get() {
return value;
}
public void set(Object newValue) {
value = newValue;
}
}
AnyBox box = new AnyBox(); box.set(“Some string”);
String boxValue = (String) box.get();
//Здесь система типов гарантирует,
//что ClassCastException не произойдет
//(но см. ссылку)
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Таким образом, класс AnyBox существует в единственном экземпляре, AnyBox<String> и AnyBox<Integer> при выполнении программы являются одним и тем же классом AnyBox (который называется raw class). Одно из следствий:
public class AnyBox<E> { void set(E newValue);
void set(Object newObject);
}
не скомпилируется, т.к. в raw-классе эти методы будут иметь одну и ту же сигнатуру.
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Другие ограничения, вызванные type erasure:
•нельзя написать new E() (потому что это было бы транслировано в new Object())
•нельзя написать new E[size] (потому что это было бы транслировано в new Object[size])
Типовые параметры существуют исключительно во время компиляции программы.
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Методы тоже могут быть generic:
public class BoxUtil { // класс – не generic
static <E> void clear(AnyBox<E> box) {
box.set(null);
}
}
AnyBox<String> box = ...;
// обычно компилятор определяет параметр E автоматически:
BoxUtil.clear(box);
// Но если нужно, можно указать вручную:
BoxUtil.<String>clear(box);
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Для типовых параметров могут быть указаны ограничения:
public class BoxUtil {
static <E extends Runnable> void runBox(AnyBox<E> box) {
E runnable = box.get(); // гарантируется, что E наследуется от Runnable
runnable.run();
}
}
BoxUtil.runBox(new AnyBox<String>()); // ошибка, String – не Runnable
BoxUtil.runBox(new AnyBox<Runnable>()); // компилируется
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Иногда нам не важно значение типового параметра (wildcard):
public class BoxUtil {
static void clearBox(AnyBox<?> box) {
box.set(null);
}
}
BoxUtil.clearBox(new AnyBox<String>());
BoxUtil.clearBox(new AnyBox<Integer>());
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
Для ? тоже могут быть указаны ограничения:
public class BoxUtil {
static void runBox(AnyBox<? extends Runnable> box) {
Runnable runnable = box.get();
runnable.run();
}
}
BoxUtil.runBox(new AnyBox<String>()); // ошибка, String – не Runnable
BoxUtil.runBox(new AnyBox<Runnable>()); // компилируется
online.mirea.ru
Центр дистанционного обучения
Generics – type erasure
public class BoxUtil {
static <E> void copyBox(AnyBox<E> to, AnyBox<E> from) {
E value = from.get();
to.set(value);
}
}
AnyBox<String> to = new AnyBox<>();
AnyBox<String> from = new AnyBox<>();
// здесь важно, что у to и from один и тот же параметр E:
BoxUtil.copyBox(to, from);
online.mirea.ru