Обобщения Java с несколькими перечислениями, реализующими интерфейс - PullRequest
4 голосов
/ 08 марта 2019

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

Глядя на Подстановочные знаки Java для нескольких классов , кажется, что

public class Main
{
    interface Foo {}

    enum First implements Foo {
        A, B, C;
    }

    enum Second implements Foo {
        X, Y, Z;
    }

    interface Bar {}

    enum Third implements Bar {
        M, N, P;
    }
    enum Fourth implements Bar {
        A, X, Z;
    }


    public static <I, T extends Enum<?> & I> 
      I enumVarArgs(Class<? extends T>... classes) 
    {
        // Do stuff and return some instance of T
        return null;
    }

    public static void main(String[] args) {
        Foo foo = enumVarArgs(First.class,
                              Second.class);
        Bar bar = enumVarArgs(Third.class,
                              Fourth.class);
    }
}

должен делать то, что я хочу. Тем не менее, это не удается скомпилировать под Java 10:

[ERROR] /me/test/src/main/java/test/Main.java:[17,42] error: unexpected type
  required: class
  found:    type parameter I
  where I,T are type-variables:
    I extends Object declared in method <I,T>enumVarArgs(Class<? extends T>...)
    T extends Enum<?>,I declared in method <I,T>enumVarArgs(Class<? extends T>...)
[INFO] 1 error

Из сообщения об ошибке я предполагаю, что Java хочет, чтобы я сделал что-то вроде T extends Enum<?> & Serializable, где я передаю фактический интерфейс, а не параметр типа. Однако мне нужно, чтобы API был общим, чтобы I оставался универсальным параметром.

Есть ли синтаксис, который делает эту работу?

Если это имеет значение, мы используем Java 10.

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

Я думаю, что вам нужно:

interface OnlyImpelents<T> {}
interface Foo extends OnlyImpelents<Foo> {}
interface Bar extends OnlyImpelents<Bar> {}

static <T extends Enum<?> & OnlyImpelents<? super T>> T enumVarArgs(T... values) {
    return values[0];
}
public static void main(String[] args) {
    Foo foo = enumVarArgs(First.A, Second.X);
}

Интерфейс маркера OnlyImpelents<T> не позволяет любому классу реализовывать Foo и Bar

Единственный способ получить enumзначения из перечисляемого класса - через отражение, которому не нужно иметь статический тип.Лично я думаю, что это не очень хороший объектно-ориентированный дизайн, использование T..., так как аргументы должны быть лучше

0 голосов
/ 08 марта 2019

Если интерфейсы - ваш дизайн, то вы можете заставить два интерфейса расширять интерфейс маркера:

interface FooBar{}

interface Foo extends FooBar {}

interface Bar extends FooBar {}

И вы можете использовать этот интерфейс маркера:

public static <T extends Enum<?> & FooBar> 
      FooBar enumVarArgs(Class<? extends T>... classes) {
    return null;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...