Подтвердить что ты не робот

Могу ли я сделать абстрактное перечисление в Java?

Ниже приведено допустимое объявление перечисления.

public enum SomeEnumClass {

    ONE(1), TWO(2), THREE(3);

    private int someInt;

    public SomeEnumClass(int someInt) {
        this.someInt = someInt;
    }
}

Но могу ли я переопределить абстрактный класс с типом перечисления?

SomeEnumClass.java

public abstract enum SomeEnumClass {

    private int someInt;

    public SomeEnumClass(int someInt) {
        this.someInt = someInt;
    }
}

OverridingEnumClass.java

public enum OverridingEnumClass extends SomeEnumClass {

    ONE(1), TWO(2), THREE(3);

}

Если нет, почему бы и нет? И что является хорошей альтернативой?

4b9b3361

Ответ 1

Нет, вы не можете; перечислены все расширения Enum, и они неявно final. Enums могут реализовывать интерфейсы, или вы можете объявить соответствующие методы непосредственно в рассматриваемом классе enum.

(Я вижу основную идею того, что вы хотите, это mixin, возможно, интерфейсы Java 8 будут немного полезнее в этом отношении.)

Ответ 2

Если вам действительно нужно "расширить перечисление", вы можете использовать шаблон Preum Java 1.5 Typesafe Enum (см. нижнюю часть http://www.javacamp.org/designPattern/enum.html), который фактически использует класс, а не перечисление. Вы теряете возможность использовать EnumSet с вашими "перечислениями", и вы теряете некоторые автоматически сгенерированные методы, такие как items(), но вы получаете возможность переопределять методы.

Пример:

// Typesafe enum pattern
public static abstract class Operator {
    public static final Operator ADD = new Operator("+") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam + secondParam;
        }
    };
    public static final Operator SUB = new Operator("-") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam - secondParam;
        }
    };
    public static final Operator MUL = new Operator("*") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam * secondParam;
        }
    };
    public static final Operator DIV = new Operator("/") {
        @Override
        public Double apply(Double firstParam, Double secondParam) {
            return firstParam / secondParam;
        }
    };

    private static final Operator[] _ALL_VALUES = {ADD, SUB, MUL, DIV};
    private static final List<Operator> ALL_VALUES = Collections.unmodifiableList(Arrays.asList(_ALL_VALUES));

    private final String operation;

    private Operator(String c) {
        operation = c;
    }

    // Factory method pattern
    public static Operator fromToken(String operation) {
        for (Operator o : Operator.items())
            if (o.operation.equals(operation))
                return o;
        return null;
    }

    public Iterable<Operator> items() {
        return ALL_VALUES;
    }

    public abstract Double apply(Double firstParam, Double secondParam); 

}

Ответ 3

В java вы не можете расширять перечисление или создавать абстрактное перечисление или даже генерировать перечисление. Если вы хотите иметь некоторую полиморфную точку расширения над вашим перечислением, вы можете применить такой шаблон.

Давайте предположим, что ваше перечисление

public enum SomeEnumClass {
    ONE, TWO, THREE;
}

И вы хотите иметь какое-то поведение, связанное с каждым значением. Но вы не хотите жестко кодировать каждый, а скорее хотите иметь возможность поставлять любые другие. Поэтому вы должны объявить интерфейс

public interface SomeEnumVisitor<P, R> {
     R one(P param);
     R two(P param);
     R three(P param);
}

Затем добавьте абстрактный метод в объявление перечисления и реализацию этого метода для каждого значения

public enum SomeEnumClass {
    ONE {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.one(param);
        }
    }, TWO {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.two(param);
        }
    }, THREE {
        @Override
        public <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param) {
            return visitor.three(param);
        }
    };
    public abstract <R, P> R accept(SomeEnumVisitor<R, P> visitor, P param);
}

Итак, вы можете создать реализацию посетителя для расширения вашего поведения enum. Например, в вашем случае вам нужно связать значение Integer с каждым значением перечисления.

public class IntValueVisitor implements SomeClassVisitor<Integer, Void> {
     @Override
     public Integer one(Void param){
         return 1;
     }

     @Override
     public Integer two(Void param){
         return 2;
     }

     @Override
     public Integer three(Void param){
         return 3;
     }    
}

И, наконец, используйте этого посетителя, где вам нужно

SomeClassEnum something = getAnyValue();
// this expression will return your particular int value associated with particular enum.
int intValue = something.accept(new IntValueVisitor(), null);

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

Чтобы упростить эту реализацию шаблона есть библиотека, которая может генерировать enum и посетителя на основе аннотации, чтобы все, что вам нужно объявить в вашем коде

@AutoEnum(value = {"one", "two", "three"}, name = "SomeEnumClass")
public interface SomeEnumMarker {}

Инструмент подойдет вам.