Использование дженериков Java с перечислениями

>>> L = [0,10,20,40]
>>> L.reverse()
>>> L
[40, 20, 10, 0]

Или

>>> L[::-1]
[40, 20, 10, 0]
18
задан Chris Boran 23 July 2009 в 18:36
поделиться

5 ответов

Yishai is right, and the magic phrase is "covariant return types" which is new as of Java 5.0 -- you can't switch on Enum, but you can switch on your Type class which extends Enum. The methods in AbstractEvent that are inherited by MyEvent are subject to type erasure. By overriding it, you're redirecting the result of getId() towards your Type class in a way that Java can handle at run-time.

11
ответ дан 30 November 2019 в 08:38
поделиться

This is not related to generics. Switch statement for enum in java can only use values of that particular enum, thus it's prohibited to actually specify enum name. This should work:

switch(event.getId()) {
   case SELECTED:
         l.selected(event);
         break;
   case SELECTION_CLEARED:
         l.unselect(event);
         break;
}

Update: Ok, here's an actual code (which I had to change a little bit to get it to compile with no dependencies) that I've copy / pasted, compiled and ran - no errors:

AbstractEvent.java

public abstract class AbstractEvent<S, T extends Enum<T>> {
    private S src;
    private T id;

    public AbstractEvent(S src, T id) {
        this.src = src;
        this.id = id;
    }

    public S getSource() {
        return src;
    }

    public T getId() {
        return id;
    }
}

MyEvent.java

public class MyEvent extends AbstractEvent<String, MyEvent.Type> {
    public enum Type { SELECTED, SELECTION_CLEARED };

    public MyEvent(String src, Type t) {
        super(src, t);
    }
}

Test.java

public class Test {
  public static void main(String[] args) {
      fireEvent(new MyEvent("MyClass.myMethod", MyEvent.Type.SELECTED));
  }

  private static void fireEvent(MyEvent event) {
        switch(event.getId()) {
            case SELECTED:
                System.out.println("SELECTED");
                break;
            case SELECTION_CLEARED:
                System.out.println("UNSELECTED");
                break;
         }
    }
}

This compiles and runs under Java 1.5 just fine. What am I missing here?

8
ответ дан 30 November 2019 в 08:38
поделиться

У меня работает.

Полная тестовая программа вырезания и вставки:

enum MyEnum {
    A, B
}
class Abstract<E extends Enum<E>> {
    private final E e;
    public Abstract(E e) {
        this.e = e;
    }
    public E get() {
        return e;
    }
}
class Derived extends Abstract<MyEnum> {
    public Derived() {
        super(MyEnum.A);
    }
    public static int sw(Derived derived) {
        switch (derived.get()) {
            case A: return 1;
            default: return 342;
        }
    }
}

Вы используете какой-то особенный компилятор?

2
ответ дан 30 November 2019 в 08:38
поделиться

In very short, because T is erased to an Enum class, not an Enum constant, so the compiled statement looks like you are switching on the result of getID being Enum, as in this signature:

Enum getId();

When you override it with a specific type, then you are changing the return value and can switch on it.

EDIT: The resistance made me curious, so I whipped up some code:

public enum Num {
    ONE,
    TWO
}
public abstract class Abstract<T extends Enum<T>> {
    public abstract T getId();
}

public abstract class Real extends Abstract<Num> {

}

public static void main(String[] args) throws Exception {
    Method m = Real.class.getMethod("getId");
    System.out.println(m.getReturnType().getName());
}

The result is java.lang.Enum, not Num. T is erased to Enum at compile time, so you can't switch on it.

EDIT:

I tested the code samples everyone is working with, and they work for me as well, so although I suspect that this underlies the issue in the more complex real code, the sample as posted actually compiles and runs fine.

2
ответ дан 30 November 2019 в 08:38
поделиться

Я только что попробовал (скопировал ваш код) и не могу воспроизвести ошибку компилятора.

public abstract class AbstractEvent<S, T extends Enum<T>>
{
    private S src;
    private T id;

    public AbstractEvent(S src, T id)
    {
        this.src = src;
        this.id = id;
    }

    public S getSource()
    {
        return src;
    }

    public T getId()
    {
        return id;
    }
}

и

public class MyEvent extends AbstractEvent<String, MyEvent.Type>
{

    public enum Type
    {
        SELECTED, SELECTION_CLEARED
    };

    public MyEvent( String src, Type t )
    {
        super( src, t );
    }


}

и

public class TestMain
{
    protected void fireEvent( MyEvent event )
    {
        switch ( event.getId() )
        {
            case SELECTED:
            break;
            case SELECTION_CLEARED:
            break;
        }
    }
}
1
ответ дан 30 November 2019 в 08:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: