Доступ к родительским методам общего enum, который реализует интерфейс

#java #generics #interface #enums

#java #общие #интерфейс #перечисления

Вопрос:

Хорошо, в настоящее время я определяю общие аргументы перечисления следующим образом:

 public interface MyInterface
{
    public int GetValue ( );
}

public enum MyEnum implements MyInterface
{
    value1(1), value2(2);

    int myvalue;

    MyEnum ( int value )
    {
        this.myvalue = value;
    }

    public int GetValue ( )
    {
        return this.myvalue;
    }
}

public class PassGeneric
{
    public void AcceptsGeneric ( Enum<? extends MyInterface> generic_enum )
    {
        generic_enum.values();                                 // Not valid
        generic_enum.GetValue();                               // Not valid
        generic_enum.getDeclaringClass().getEnumConstants();   // Valid
        ((Enum<?>)generic_enum).values();                      // Not Valid
        ((MyInterface)generic_enum).GetValue();                // Valid
    }
}
  

Я просто пытаюсь понять, почему спецификатор типа Enum<? extends MyInterface> не позволяет мне 1) напрямую обращаться к MyInterface методам и 2) напрямую обращаться к методам перечисления, таким как .values() .

Приведение работает для доступа к MyInterface методам, но для меня нецелесообразно указывать, что общий тип расширяется MyInterface , поскольку по-прежнему разрешено просто Enum<? extends MyInterface> заменять Enum<?> и приводить объект как (MyInterface) .

Если я неправильно истолковал использование дженериков и реализацию extends , может ли кто-нибудь объяснить мне, как правильно явно указать generic, реализующий данный интерфейс.

Комментарии:

1. Есть ли какая-либо причина, по которой вы бы просто использовали MyInterface в качестве параметра?

2. Потому что я также хочу получить доступ к методам перечисления, таким как .values()

Ответ №1:

Вы не можете получить доступ values() , потому что это не метод экземпляра; это статический метод, принадлежащий типу enum . Таким образом, передача экземпляра суперкласса Enum не дает вам необходимой информации.

Что касается методов интерфейса, declaring Enum<? extends MyInterface> объявляет определенную общую информацию о перечислении, но не сообщает компилятору, который generic_enum сам является экземпляром MyInterface .

Если вы хотите объявить, что generic_enum реализует MyInterface , вы должны сделать именно это:

 public void AcceptsGeneric ( MyInterface generic_enum )
  

Если по какой-либо причине вам нужно знать, что он реализует, MyInterface и это enum, вы можете объявить свой метод следующим образом:

 public <T extends Enum<T> amp; MyInterface> void AcceptsGeneric ( T generic_enum )
  

Комментарии:

1. Разве не должен быть включен общий параметр Enum ?

Ответ №2:

Объявление параметра метода как Enum<? extends MyInterface> generic_enum ограничивает методы generic_enum , к которым вы можете получить доступ без приведения к методам Enum . Аргумент type не изменяет тип на что-то другое, кроме Enum . Поэтому эти строки недопустимы:

 generic_enum.values();
generic_enum.GetValue();
((Enum<?>)generic_enum).values(); // ((Enum<?>)generic_enum) still of type Enum
  

Теперь давайте посмотрим на следующую строку:

 ((MyInterface)generic_enum).GetValue();
  

Нет причин не разрешать приведение. Расширение классов Enum может реализовываться MyInterface . Поэтому нет причин запрещать это приведение. (Компилятор не запрещает это только потому, что a ClassCastException может произойти во время выполнения).

Теперь оставшаяся строка:

 generic_enum.getDeclaringClass().getEnumConstants();
  

Поскольку generic_enum имеет тип Enum<? extends MyInterface> , возвращаемый тип generic_enum.getDeclaringClass() is Class<? extends MyInterface> . Поскольку Class содержит метод getEnumConstants() , строка является допустимой.

Поскольку вы все еще можете получить доступ к значениям из класса generic_enum , вы можете объявить AcceptsGeneric как

 public void AcceptsGeneric(MyInterface generic_enum)
  

или

 public<T extends Enum<T> amp; MyInterface> void AcceptsGeneric(T generic_enum)
  

и использовать

 generic_enum.getClass().getEnumConstants()
  

чтобы получить значения.