Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
3. generics.pdf
Скачиваний:
10
Добавлен:
09.06.2015
Размер:
641.09 Кб
Скачать

Обобщённые классы

©

NetCracker Technology Corp.

/

Применение обобщённых классов

.

Область применения параметризованных классов огромна:

. конечно, коллекции и вообще любого рода контейнеры:

List<Integer>, Set<Long>, Map<String, Runnable>,

Future<HttpResponse>, Optional<Model>;

. компараторы:

public interface Comparator<T> { int compare(T left, T right);

}

. объекты-функции:

public interface Function<F, T> { T apply(F arg);

}

public interface Callable<T> { T call() throws Exception;

}

.

©

NetCracker Technology Corp.

/

Применение обобщённых классов

.

. разного рода провайдеры:

public interface Provider<T> { T get();

}

public interface ThrowingProvider<T, E extends Throwable> { T get() throws E;

}

. обобщённые DAO:

public abstract class GenericDAO<T, ID> { protected GenericDAO(Class<T> clazz) { ... } public T findById(ID id) { ... }

}

. конвертеры:

 

public interface StringConverter<T> {

 

T fromString(String s);

 

String toString(T obj);

 

}

 

.

...тысячи их.

© NetCracker Technology Corp.

/

Синтаксис

.

Синтаксис объявления класса с ти́повыми параметрами:

public class SomeClass<T , T , ...> {

...

}

Внутри тела класса типовые параметры могут использоваться как обычные имена классов (за некоторым исключением).

Ясно, что параметризованными могут быть также и интерфейсы и абстрактные классы.

.

©

NetCracker Technology Corp.

/

Наследование

.

От обобщённых классов/интерфейсов можно наследоваться:

public interface Function<F, T> { T apply(F arg);

}

public class Uppercaser extends Function<String, String> { @Override public String apply(String arg) {

return arg.toUpperCase();

}

}

Наследующий класс также может быть обобщённым:

public abstract class Stringer<T> extends Function<T, String> { @Override public String apply(T arg);

}

.

©

NetCracker Technology Corp.

/

Верхние границы

.

Проблема: мы ничего не можем делать с переменными, типом которых параметризуется класс (кроме операций над Object):

public class OperationsWrapper<T> { private final T inner;

public OperationsWrapper(T inner) { this.inner = inner; } public double doubleSquare() {

// Какой метод вызвать? double value = inner.???(); return value*value;

}

public int truncateAndAdd(T other) { int truncated = inner.???(); return truncated + other.???();

}

}

Доступная информация — inner является Object’ом, поэтому мы можем вызывать на нём только методы класса Object.

.

©

NetCracker Technology Corp.

/

Верхние границы

.

Решение: верхние границы для типовых параметров:

public class OperationsWrapper<T extends Number> { private final T inner;

public OperationsWrapper(T inner) { this.inner = inner; } public double doubleSquare() {

//Работает, так как T является подклассом Number,

//у которого есть метод doubleValue()

double value = inner.doubleValue(); return value*value;

}

public int truncateAndAdd(T other) {

// Аналогично

int truncated = inner.intValue(); return truncated + other.intValue();

}

}

На переменных с таким «ограниченным» типом мы можем вызывать соответствующие методы.

.

©

NetCracker Technology Corp.

/

Больше верхних границ

.

В верхней границе можно также указывать несколько типов:

public class OnceAppender<T extends Appendable & AutoCloseable> { private final T inner;

public OnceAppender(T inner) { this.inner = inner; }

public void appendAndClose(String s) throws Exception {

//Метод append() объявлен в Appendable,

//метод close() --- в AutoCloseable inner.append(s);

inner.close();

}

}

.

©

NetCracker Technology Corp.

/

Сложные верхние границы

.

В верхней границе можно использовать типы, параметризованные ограничиваемым типом:

public interface Comparable<T> { int compareTo(T other);

}

public class TrivialComparator<T extends Comparable<T>> extends Comparator<T> {

private final T inner;

public TrivialComparator(T inner) { this.inner = inner; } @Override public int compare(T left, T right) {

return left.compareTo(right);

}

}

Такое нужно в случае, если обобщённый тип (в данном случае Comparable<T>) должен использовать объекты собственного типа.

.

©

NetCracker Technology Corp.

/

Примитивные типы

.

В качестве типовых параметров нельзя использовать примитивные типы:

List<int> list = new ArrayList<>(); // Ошибка компиляции

Для списка чисел и прочего нужно использовать обёртки:

List<Integer> list = new ArrayList<>();

Страдает производительность; есть библиотеки производительных коллекций примитивных типов (Trove).

.

©

NetCracker Technology Corp.

/