Перечисление‹? расширяет интерфейс›

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

interface Fooable
{
  void someCommonMethod();
}

enum E1 implements Fooable
{
   // some enumuerations and a definition for someCommonMethod()
}

enum E2 implements Fooable
{
   // some different enumerations and a different definition for someCommonMethod()
}

а затем использовать это в другом месте, обеспечив, чтобы переменная была Enum и реализовывала интерфейс. Так что что-то в духе..

bar(Enum<? extends Fooable> fe)
{
  fe.ordinal();
  fe.someCommonMethod();
}

Однако до сих пор мне, похоже, приходилось приводить fe, чтобы рассматривать его как реализацию интерфейса, т. Е.

bar(Enum<? extends Fooable> fe)
{
  fe.ordinal();
  ((Fooable)fe).someCommonMethod();
}

и хотя это должно быть безопасно... это кажется неоптимальным, и я могу что-то упустить из виду. Конечно, если я попытаюсь просто передать параметр как Fooable, то я закончу кастинг, чтобы рассматривать его как Enum, и это не только не дает никакого результата, но теперь я даже не в безопасности. См. следующее:

bar(Fooable fe)
{
  // potentially unsafe cast!
  ((Enum<?>)fe).ordinal();
  fe.someCommonMethod();
}

Есть ли что-то, что я пропускаю, или это

Enum<? extends Fooable>

примерно так близко к «хорошему» решению, как я получу?

Я относительно новичок в Java и все еще ловлю себя на том, что пытаюсь использовать его как C или C++, поэтому, если я отношусь к нему как к молотку, а не к пиле, или упускаю из виду что-то глупо простое, не стесняйтесь указывать на это :)


person Khanmots    schedule 10.08.2012    source источник


Ответы (2)


Один из вариантов, который у вас есть, — это добавить любые методы из Enum, которые вам нужны, в Fooable или создать новый интерфейс, расширяющий Fooable и добавляющий нужные вам методы Enum.

Пример:

interface Fooable {
   void someCommonMethod();
}

interface FooableEnum extends Fooable {
   int ordinal();
}

enum E1 implements FooableEnum {
   // Implement someCommonMethod.
   // ordinal() is already implemented by default.
}

Как только вы это сделаете, вы можете использовать FooableEnum в качестве типа параметра в сигнатуре вашего метода и не беспокоиться ни о каких общих вещах.

person Mike Deck    schedule 10.08.2012
comment
Я думал об этом, но у меня были оговорки по поводу его поведения по отношению к values(), возможно, стоит вернуться, хотя сейчас я не могу выкопать действительное бронирование... - person Khanmots; 11.08.2012
comment
Это требует ненужного интерфейса. - person Håvard Geithus; 11.08.2012
comment
@Майк, чем больше я думаю об этом, тем больше считаю, что это правильный путь. Мое требование состоит не в том, что тип является перечислением, а в том, чтобы он имел поведение перечисления. Я также убедил себя, что функция values() не будет проблемой, и я был глуп. - person Khanmots; 11.08.2012
comment
@Havard, зависит от того, как используется интерфейс. Int ordinal() может быть помещен в исходный интерфейс Fooable, но если этот интерфейс Fooable использовался в другом месте без требования быть перечислением, которое я пытаюсь навязать здесь, второй интерфейс, как это сделано здесь, может быть полезным. В моем случае я, вероятно, буду комбинировать два; но показать его отдельно было выгодно. - person Khanmots; 11.08.2012

Это означает, что T расширяет Enum и реализует Fooable:

<T extends Enum<T> & Fooable>

Таким образом, ваш метод может быть записан как:

<T extends Enum<T> & Fooable> void bar(T fe) {
    fe.ordinal();
    fe.someCommonMethod();
}
person Håvard Geithus    schedule 10.08.2012
comment
да, но я понимаю, что это только для использования при объявлении универсального, не определяющего параметр для метода? - person Khanmots; 11.08.2012
comment
@Khanmots Сами методы могут быть универсальными. - person Paul Bellora; 11.08.2012
comment
Не думал об этом подходе... экспериментировал с универсальным интерфейсом с T, расширяет Enum‹T› и Fooable‹T›, но, возможно, придется поковыряться с созданием общего класса, чтобы все его методы может иметь T с обоими ограничениями... - person Khanmots; 11.08.2012
comment
К сожалению, похоже, что это просто создает дополнительные непроверенные приведения в моей кодовой базе, а именно некоторые методы в интерфейсе Fooable возвращают перечисления, которые затем будут присвоены переменной типа T... и из-за стирания типа это требует непроверенного приведения. Похоже, что это обеспечит соблюдение двойного ограничения во время компиляции, хотя... придется подумать об этом. - person Khanmots; 11.08.2012
comment
Как это изменит возвращаемые типы методов в интерфейсе Fooable? - person Håvard Geithus; 11.08.2012
comment
Рассмотрим следующую строку: T fe2 = fe.someOtherCommonMethod(); Даже без учета таких вещей, как ковариантные возвращаемые типы, я почти уверен, что стирание типа приведет к тому, что среда выполнения не сможет гарантировать, что тип, возвращаемый someOtherCommonMethod(), соответствует типу T. Или я ошибаюсь в этом? ? - person Khanmots; 11.08.2012