Почему я не могу вернуть enum с интерфейсом?

Посмотрите на этот ответ. Все хорошо, кроме этого:

public <E extends Enum<E> & MyInterface> E getParametrizedEnum() {
    String someString = "..."
    return MyEnum.valueOf(someString); //compile error here
}

Идея Intellij говорит мне: «Требуется E, найден com.mypackage.MyEnum».

Должны быть брошены так:

public <E extends Enum<E> & MyInterface> E getParametrizedEnum() {
    String someString = "..."
    return (E) MyEnum.valueOf(someString); //compile error here
}

Есть ли способ вернуть параметризованное перечисление с интерфейсом без приведения?


person Cherry    schedule 04.02.2016    source источник
comment
Пожалуйста, покажите нам MyEnum   -  person Henry    schedule 04.02.2016
comment
Похоже, MyEnum не реализует MyInterface. Но если это так, почему бы просто не использовать MyEnum в качестве возвращаемого типа? Или вы можете вернуть разные типы перечислений?   -  person shmosel    schedule 04.02.2016
comment
обратите внимание, что вы не получаете никаких гарантий типа для этого метода. Его возвращаемое значение может быть присвоено буквально любому ссылочному типу без ошибки компиляции: java.awt.Point p = getParametrizedEnum(); см. stackoverflow.com/q/338887/3385618   -  person Bewusstsein    schedule 04.02.2016


Ответы (1)


Проблема в том, что метод не возвращает MyEnum, он возвращает некоторый класс, который расширяет как Enum, так и MyInterface. Даже если MyEnum удовлетворяет этим ограничениям, могут существовать другие перечисления, которые также реализуют MyInterface, и они не обязательно совместимы по назначению с MyEnum.

Рассмотрим следующую программу:

interface MyInterface {} 
enum MyEnum implements MyInterface {
    A, B, C
}
enum YourEnum implements MyInterface {
    D, E, F
}

public class Foo
{
    public <E extends Enum<E> & MyInterface> E getParametrizedEnum() {
        String someString = "A";
        return (E) MyEnum.valueOf(someString); 
    }

    public static void main(String... args) {
        Foo foo = new Foo();
        YourEnum b = foo.getParametrizedEnum(); // Ooops!
    }
}

Он прекрасно компилируется, но во время выполнения выдает ClassCastException!

Но если вы все равно возвращаете MyEnum, зачем вам дженерики? Ты можешь сделать:

public MyEnum getParametrizedEnum() {
    String someString = "..."
    return MyEnum.valueOf(someString); 
}
person Hoopje    schedule 04.02.2016
comment
Почему они должны быть совместимы по назначению? Я могу вернуть ArrayList из метода, возвращающего Iterable, хотя есть и другие классы, реализующие Iterable. Чем отличается эта ситуация? Что может пойти не так, если компилятор разрешит этот оператор return? - person Thomas; 04.02.2016
comment
Но они совместимы по назначению. Iterable<String> a = new ArrayList<>() совершенно законно. - person Hoopje; 04.02.2016
comment
О, теперь я вижу. Пример, который вы добавили, иллюстрирует, спасибо. - person Thomas; 04.02.2016
comment
Основная проблема заключается в том, чтобы вернуть 2 перечисления вместо одного. Вот почему мне нужен здесь интерфейс, чтобы ограничить числа перечислений. Вернуть интерфейс можно, но переключение enum в этом случае теряется :( - person Cherry; 04.02.2016