Объединение перечислений и использование getter для возврата указанного перечисления

Скажем, у меня есть 2 разных набора перечислений: фрукты и овощи.

public static enum Fruits{
    APPLE ("Apple"),
    PEAR ("Pear");

    //constructor
    //getName()
    ... 
}
public static enum Vegetables{
    CARROT ("Carrot"),
    LETTUCE ("Lettuce");

    //constructor
    //getName()
    ...
}

Я показываю все это в JComboBox. После того, как кто-то что-то выбирает, я хочу использовать метод getter, чтобы вернуть Enum.

Для одного перечисления я сделал бы что-то вроде:

public static Fruits getEnum(String name) {
  for(Fruits fruit: Fruits.values()) {
    if(name.equals(fruit.getName())) {
      return fruit;
    }
  }
  return null;
}

Любые идеи, каков тип возврата? Я пытался использовать Enum вместо Fruits. Когда я это делаю, у меня нет доступа к методам getName().

Ответ 1

Вот еще одна демонстрация того, что вы ищете. Разница между этим и предыдущими решениями заключается в том, что эта модель является более общей и многоразовой. Это фактически выходит за рамки первоначальной проблемы, чтобы показать некоторые другие преимущества этого подхода. Поэтому вы можете просто прокомментировать биты, которые вам не нужны. Я также прикрепляю unit test для демонстрации поведения.

Итак, в основном для поиска имени Apple или Apple в одном из этих перечислений просто напишите:

FruitVeg<?> fvg = getEnum("APPLE", Fruits.class, Vegetables.class);

FruitVeg<> - это интерфейс, который позволяет также использовать внутри Enum, этот интерфейс позволяет делать некоторые очень интересные вещи с перечислениями ниже. Вот лишь некоторые из вещей, которые вы могли бы сделать с этим:

  • Enum.valueOf(fvg.getDeclaringClass(), fvg.name()): возвращает значение перечисления, например. APPLE

  • fvg.getRaw(): возвращает значение перечисления, например. APPLE

  • fvg.name(): возвращает enum String Name, например. APPLE

  • fvg.getFriendlyName(): например. Apple

  • fvg.getDeclaringClass(): возвращает Class<Enum<?>>, например. класс ox.dummy.dummyTest $Fruits

  • fvg.getClass(): класс ox.dummy.dummyTest $Fruits возвращает Class<?>

  • EnumSet.allOf(fvg.getDeclaringClass())): например. [APPLE, PEAR]

Вот код

   @Test
public void doSimpleTest() throws Exception {

    FruitVeg<?> fvg = getEnum("APPLE", Fruits.class, Vegetables.class);
    log.info("{} : {} : {} : {} : {}", fvg.name(), fvg.getFriendlyName(), fvg.getClass(), fvg.getDeclaringClass(), EnumSet.allOf(fvg.getDeclaringClass()));
    log.info("get enum: {} ", Enum.valueOf(fvg.getDeclaringClass(), fvg.name()));

}


public interface FruitVeg<T extends Enum<T>> {
    String name();

    String getFriendlyName();

    Class<T> getDeclaringClass();

    T getRaw();

}

enum Fruits implements FruitVeg<Fruits> {
    APPLE("Apple"),
    PEAR("Pear");

    Fruits(String friendlyName) {
        this.friendlyName = friendlyName;
    }

    private final String friendlyName;

    @Override
    public String getFriendlyName() {
        return friendlyName;
    }
    @Override
    public Fruits getRaw() {
        return this;
    }
}


enum Vegetables implements FruitVeg<Vegetables> {
    CARROT("Carrot"),
    LETTUCE("Lettuce");

    Vegetables(String friendlyName) {
        this.friendlyName = friendlyName;
    }

    private final String friendlyName;

    @Override
    public String getFriendlyName() {
        return friendlyName;
    }

    @Override
    public Vegetables getRaw() {
        return this;
    }
}


public static FruitVeg<?> getEnum(String name, Class<? extends FruitVeg<?>>... fvgClasses) {
    for (Class<? extends FruitVeg<?>> fruitVegCLass : Arrays.asList(fvgClasses)) {
        for (FruitVeg<?> fvg : fruitVegCLass.getEnumConstants()) {
            if (name.equals(fvg.name()) || name.equals(fvg.getFriendlyName())) {
                return fvg;
            }
        }
    }
    return null;
}

Ответ 2

Вариант 1.
Создайте один метод, который возвращает Enum

public static Enum getEnum(String name) {
    Enum selectedEnum = null;
    for (Fruits fruit : Fruits.values()) {
        if (name.equals(fruit.getName())) {
            selectedEnum = fruit;
        }
    }

    for (Vegetables vegetables : Vegetables.values()) {
        if (name.equals(vegetables.getName())) {
            selectedEnum = vegetables;
        }
    }
    return selectedEnum;
}

и для получения имени перечисления вы можете использовать этот метод

public static String getName(final Enum value) {
    String name = null;
    if (value instanceof Fruits) {
        name = ((Fruits) value).getName();
    } else if (value instanceof Vegetables) {
        name = ((Vegetables) value).getName();
    }
    return name;
}

Вариант 2.
Вы можете объединить 2 перечисления как

public static enum FruitsAndVegitables{
    APPLE ("Apple" , true),
    PEAR ("Pear", true),
    CARROT ("Carrot", false),
    LETTUCE ("Lettuce", false);

    private String name;
    private boolean isFurit;
    //constructor
    //getName()
    ... 
}

Ответ 3

Перечислите сами перечисления как значения. Затем используйте getSelectedItem для извлечения выбранного объекта и выполните тест, чтобы узнать, какой тип объекта есть.

Сделайте возвращаемым типом своего метода Object, а не перечислением определенного типа. Это устранит вашу проблему.

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

public enum FoodType{FRUIT, VEGETABLE}
public class Food{
    FoodType type;
    String name;
    public Food(FoodType type, String name){
        this.type = type;
        this.name = name;
    }
    public String toString(){return this.name;}
}

//and then when you want to use it...
Food lettuce = new Food(FoodType.VEGETABLE, "Lettuce");
Food berry = new Food(FoodType.BERRY, "Berry");
comboBox.add(lettuces);
comboBox.add(berry);

И добавьте только теги Food в JComboBox. Возвращайте элементы Food при выборе и проверяйте тип продукта, используя перечисление FoodType.

Ответ 4

Похоже, что вы ищете возможность применить наследование к enums, но это невозможно в java, поскольку enums implicity extend java.lang.Enum и java не поддерживает множественное наследование.

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

Ответ 5

Вы можете использовать Object вместо явного использования Fruit или Vegetables

public static Object getEnum(String name) 
{    
    for(Fruits fruit: Fruits.values()) 
    {
        if(name.equals(fruit.getName())) 
        {
              return fruit;
        }
    }
    for(Vegetables vege: Vegetables.values()) 
    {
        if(name.equals(Vegetables.getName())) 
        {
              return vege;
        }
    }
  return null;
}

Тем не менее, это означает, что вам придется сравнить и применить результат к тому, что вы хотите

Object o = getEnum("Carrot")
if(o instanceof Vegetable)
{
     Vegetable v = (Vegetable)o;
     v.getName();
}
//.. and again for fruit