|
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