【问题标题】:Multiple enum initialization多个枚举初始化
【发布时间】:2015-09-21 16:02:31
【问题描述】:

一直在尝试构建一个我想或多或少保持静态的类,因此我可以按类别选择不同的元素: MyClass.CategoryOne.ELEMENTONE

我为实现这一目标而构建的是

public class ElementClass {
public static List<Element> elementList = new ArrayList<Element>();

public enum Animals {
    DOG(new Dog()),
    CAT(new Cat());

    private Animal element;

    private Animals (Animal element) {
        this.element= element;

        addToList(element);
    }

    public Animal getElement() {
        return element;
    }
}

public enum Plants {
    TREE(new Tree());
    BUSH(new Bush());

    private Plant element;

    private Plants (Plant element) {
        this.element= element;

        addToList(element);
    }

    public Plant getElement() {
        return element;
    }
}

public enum Buildings {
    FENCE(new Fence()),
    BRIDGE(new Bridge()),

    private Building element;

    private Buildings(Building element) {
        this.entity = element;

        addToList(element);
    }

    public Building getElement() {
        return element;
    }
}

private static void addToList(Element element) {
    if (!elementList.contains(element)) {
        elementList.add(element);
    }
}

}

问题在于它没有完全初始化(在代码中的某个位置,Plants 枚举没有添加到列表中,而其余的则添加了)。

我可以使用以下方法“修补”它:

private static ElementClass instance = new ElementClass ();

private ElementClass () {
    ElementClass.Animals.values();
    ElementClass.Plants.values();
    ElementClass.Buildings.values();
}

public static ElementClass getInstance() {return instance;}

并提前调用实例,但我想知道.. 有没有办法做到这一点而无需添加没有其他目标的值调用?我想我的方法不是最好的,但我不知道其他方法可以让我以这种方式访问​​每个元素(例如 ElementClass.Animals.DOG)。

如果方法还不错,有没有办法在课程开始时遍历所有枚举?或将其添加到 for 循环中的方法(我不知道 getClass().getFields() 是否可以帮助,或者我是否可以将字段强制转换为枚举以获取值)。

【问题讨论】:

  • 代码中的某个点向我们展示那个代码。
  • 你是如何子类化枚举的?我认为这在 Java 中是不可能的。

标签: java enums


【解决方案1】:

一起跳过枚举并使用静态内部类怎么样?例如:

public final class ElementClass {

public static void main(String[] args) {
    ElementClass.Animal.DOG.makeSound();
    ElementClass.Animal.CAT.makeSound();
}


public static abstract class Animal {
    public static Animal DOG = new Dog();
    public static Animal CAT = new Cat();

    public abstract void makeSound();
  }

}

// NOTE: Put in separate file if it needs to be accessible outside package. 
final class Dog extends ElementClass.Animal {

    @Override
    public void makeSound() {
        System.out.println("WOOF!");
    }
}

final class Cat extends ElementClass.Animal {
    @Override
    public void makeSound() {
        System.out.println("MEOW!");
    }

}

这也避免了拥有静态集合和可公开访问的集合这两种反模式。

您没有指定任何给定类别的元素必须是可迭代的,所以我没有将其作为要求包括在内,只是您可以按照您的指定处理它们。

【讨论】:

    【解决方案2】:

    这段代码有几个问题。

    1. 它使用非最终静态字段。这几乎总是一种代码味道。这个列表应该是最终的:任何代码都可以用另一个替换列表
    2. 该列表是可修改的。任何代码都可以从列表中删除元素、对其进行排序或将元素添加到列表中。它应该被包裹在一个不可修改的视图中
    3. 当类加载器加载每个枚举时,列表会延迟填充。看来您希望它急切地加载。这也会导致线程安全问题。
    4. 列表由枚举构造函数填充。那里不应该这样做。

    我的建议是,从构造函数中删除 addToList 调用,并使用如下内容:

    public static final List<Element> ELEMENT_LIST = createList();
    
    private static List<Element> createList() {
        List<Element> result = new ArrayList<>();
        List<HasElement> enumValues = new ArrayList<>();
        enumValues.addAll(Arrays.asList(Animal.values));
        enumValues.addAll(Arrays.asList(Plant.values));
        ...
        for (HasElement hasElement : enumValues) {
            result.add(hasElement.getElement());
        }
        return Collections.unmodifiableList(result);
    
    }
    
    interface HasElement {
        Element getElement();
    }
    
    public enum Animals implements HasElement {
        DOG(new Dog()),
        CAT(new Cat());
    
        private Animal element;
    
        private Animals (Animal element) {
            this.element = element;
        }
    
        @Override
        public Animal getElement() {
            return element;
        }
    }
    

    【讨论】:

      【解决方案3】:

      问题是类初始化被推迟到第一次使用。

      您可能会以某种形式使用枚举类本身。

      public class ElementClass {
      
          public static List<Class<Enum<?>>> enumClasses() {
              List<Class<Enum<?>>> clazzes = new ArrayList<>();
              Collections.addAll(clazzes,
                  Animals.class, Plants.class, Buildings.class);
              return clazzes;
          }
      

      手动添加每个类似乎开销很小。

      然后:

      for (Class<Enum<?>> clazz : ElementClass.enumClasses()) {
           // Getting a single value:
           Object dog = Enum.valueOf(clazz, "DOG");
      
           // Getting all values:
           Object[] all = clazz.getEnumConstants();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-05
        • 1970-01-01
        • 2011-12-31
        • 2011-05-23
        • 2014-01-19
        相关资源
        最近更新 更多