#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()
чтобы получить значения.