Spec-Zone .ru
спецификации, руководства, описания, API
|
Могут быть времена, когда Вы хотите ограничить типы, которые могут использоваться в качестве параметров типа в параметризованном типе. Например, метод, который работает на числах, мог бы только хотеть принять экземпляры Number
или его подклассы. Это - то, для чего ограниченные параметры типа.
Чтобы объявить ограниченный параметр типа, перечислите имя параметра типа, сопровождаемое extends
ключевое слово, сопровождаемое его верхней границей, которая в этом примере является Number
. Отметьте что в этом контексте, extends
используется в общем смысле означать, что любой "расширяется" (как в классах) или "реализации" (как в интерфейсах).
public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public <U extends Number> void inspect(U u){ System.out.println("T: " + t.getClass().getName()); System.out.println("U: " + u.getClass().getName()); } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); integerBox.set(new Integer(10)); integerBox.inspect("some text"); // error: this is still String! } }
Изменяя наш универсальный метод, чтобы включать этот ограниченный параметр типа, компиляция теперь перестанет работать, начиная с нашего вызова inspect
все еще включает a String
:
Box.java:21: <U>inspect(U) in Box<java.lang.Integer> cannot be applied to (java.lang.String) integerBox.inspect("10"); ^ 1 error
В дополнение к ограничению типов можно использовать, чтобы инстанцировать универсального типа, ограниченные параметры типа позволяют Вам вызывать методы, определенные в границах:
public class NaturalNumber<T extends Integer> { private T n; public NaturalNumber(T n) { this.n = n; } public boolean isEven() { return n.intValue() % 2 == 0; } // ... }
Метод isEven вызывает метод intValue, определенный в Integer class через n.
Предыдущий пример иллюстрирует использование параметра типа со связанным синглом, но у параметра типа могут быть многократные границы:
<T extends B1 & B2 & B3>
Переменная типа с многократными границами является подтипом всех типов, перечисленных в связанном. Если одной из границ является class, она должна быть определена сначала. Например:
Class A { /* ... */ } interface B { /* ... */ } interface C { /* ... */ } class D <T extends A & B & C> { /* ... */ }
Если связанный A не определяется сначала, Вы получаете ошибку времени компиляции:
class D <T extends B & A & C> { /* ... */ } // compile-time error