Подстановочные знаки Java с несколькими классами - PullRequest
350 голосов
/ 14 апреля 2009

Я хочу иметь объект Class, но я хочу заставить любой класс, который он представляет, расширить класс A и реализовать интерфейс B.

Я могу сделать:

Class<? extends ClassA>

Или:

Class<? extends InterfaceB>

но я не могу сделать оба. Есть ли способ сделать это?

Ответы [ 2 ]

556 голосов
/ 14 апреля 2009

На самом деле, вы можете делать то, что вы хотите. Если вы хотите предоставить несколько интерфейсов или интерфейсы класса плюс, вы должны иметь подстановочный знак примерно так:

<T extends ClassA & InterfaceB>

См. Учебник Generics на сайте sun.com, в частности, раздел Параметры ограниченного типа внизу страницы. Вы можете указать несколько интерфейсов, если хотите, используя & InterfaceName для каждого, который вам нужен.

Это может быть сколь угодно сложно. Для демонстрации см. Декларацию JavaDoc Collections#max, которая (заключена в две строки):

public static <T extends Object & Comparable<? super T>> T
                                           max(Collection<? extends T> coll)

почему так сложно? Как сказано в FAQ по Generics Java: Для сохранения бинарной совместимости .

Похоже, что это не работает для объявления переменных, но работает, когда устанавливает общую границу для класса. Таким образом, чтобы сделать то, что вы хотите, вам, возможно, придется прыгнуть через несколько обручей. но ты можешь сделать это. Вы можете сделать что-то вроде этого, установив общую границу для своего класса, а затем:

class classB { }
interface interfaceC { }

public class MyClass<T extends classB & interfaceC> {
    Class<T> variable;
}

, чтобы получить variable, у которого есть ограничение, которое вы хотите. Для получения дополнительной информации и примеров посетите страницу 3 Generics in Java 5.0 . Обратите внимание, что в <T extends B & C> имя класса должно идти первым, а интерфейсы - последующими. И, конечно, вы можете перечислить только один класс.

15 голосов
/ 13 ноября 2013

Вы не можете сделать это с параметрами «анонимного» типа (то есть с подстановочными знаками, которые используют ?), но вы можете сделать это с параметрами «именованного» типа. Просто объявите параметр типа на уровне метода или класса.

import java.util.List;
interface A{}
interface B{}
public class Test<E extends B & A, T extends List<E>> {
    T t;
}
...