Java Generics Подстановочные знаки с несколькими классами

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

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

Class<? extends ClassA>

Или:

Class<? extends InterfaceB>

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

Ответ 1

Собственно, вы можете делать то, что хотите. Если вы хотите предоставить несколько интерфейсов или интерфейсы класса плюс, вам нужно, чтобы ваш шаблон выглядел примерно так:

<T extends ClassA & InterfaceB>

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

Это может быть усложнено. Чтобы продемонстрировать, см. Объявление JavaDoc Collections#max, которое (завернутое на две строки):

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

почему так сложно? Как указано в часто задаваемых вопросах Java Generics: Чтобы сохранить двоичную совместимость.

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

class classB { }
interface interfaceC { }

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

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

Ответ 2

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

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

Ответ 3

Параметр типа может иметь несколько границ. Например

public static <T extends Number & Comparable<T>> T maximum(T x, T y, T z)

T - это параметр типа, передаваемый универсальному классу Box, и он должен быть подтипом класса Number и должен влиять на сопоставимый интерфейс. Если класс передается как связанный, он должен быть передан прежде, чем интерфейс, иначе произойдет ошибка времени компиляции.

public static <T extends Number & Comparable<T>> T maximum(T x, T y, T z) {
    T max = x;      
    if(y.compareTo(max) > 0) {
        max = y;   
    }

    if(z.compareTo(max) > 0) {
        max = z;                    
    }
    return max;      
}

Узнайте больше здесь