Java中的类c枚举
C-like enum in Java
我试图在c++中找到一个等价的Java:
enum {
ANIMAL_CAT = 0,
ANIMAL_RAT,
ANIMAL_BAT, ...
NUM_ANIMALS
};
Animal animals[NUM_ANIMALS];
animals[ANIMAL_CAT].mNumLegs = 4;
animals[ANIMAL_RAT].mNumLegs = 4; ...
我知道这不是世界上最漂亮的事情,但是我可以在枚举的任何地方添加一个新的ANIMAL_xxx,然后所有下面的条目都会自动调整。在Java中是否有一种干净的方法来做到这一点?
谢谢你的回复,但我可能暗示了一个比我想要的更简单的东西。
我正在制作一款带有物理、AI引擎等元素的游戏。我试图整合每种实体类型所需的所有信息(有些实体只有物理表现,而有些实体同时具有物理和AI等),以便我可以轻松添加/修改类型(所以,动物是一个糟糕的例子,因为我可能需要岩石,植物等)。
我使用一个类来存储类型信息,而其他类依赖于该类来查找属性(尺寸,位图索引,hasAi等…)最后,我试图清理类似于下面的东西,同时允许我轻松地添加新类型:
class UnitTypeInfo {
UnitTypeInfo() {
mTypes = new TypeInfo[NUM_TYPES];
// and allocate...
// initialize TypeInfos here
mTypes[TYPE_CAT].mType = TYPE_CAT;
mTypes[TYPE_CAT].mMass = 10.0f;
mTypes[TYPE_CAT] ...
mTypes[TYPE_ROCK].mType = TYPE_ROCK;
...
}
public class TypeInfo {
public int mType;
public int mRawResourceHandle;
public float mMass;
public Vector2d mDimensions;
public float mHealth;
public boolean mHasAi;
...
}
public static final int TYPE_CAT = 0;
public static final int TYPE_ROCK = 1;
public static final int TYPE_TREE = 2; ...
public static final int NUM_TYPES = ???; // the last TYPE_ + 1
public TypeInfo mTypes[];
}
现在,这看起来像是某种XML实现可能是"正确"的事情,但我不确定如何做到这一点(对Java来说是新的)。无论如何,其他类可以很容易地使用unitTypeInfo.mTypes[UnitTypeInfo.TYPE_CAT]。mMass(实例化)来查找猫的质量。但是,如果我想在TYPE_CAT定义下面添加一个TYPE_DOG,我必须更新它下面的所有内容(我知道这很懒,但是让我们考虑一下还有更多的类型)
枚举在c++中为这个问题提供了一个简单的解决方案,但是在Java中,我现在能想到的最简单的解决方案需要类似这样的东西:unitTypeInfo.mTypes[UnitTypeInfo.mTypeEnum.TYPE_CAT.ordinal()]。mMass -虽然我认为这并没有比我已经很糟糕的解决方案更糟糕,但它确实增加了更多的间接和实际的方法调用(对于大多数来源似乎不鼓励的方法)。
还有一件事,我希望能够调用一个开关(类型),所以这可能也限制了可能的解决方案。
无论如何,我开始有了一个想法,一定有一个更好的解决整个问题的办法。有什么建议吗?"Classic" java在这种情况下总是使用"static final int ANIMAL_CAT = 0;"
JDK 1.5引入了"类型安全的枚举":
http://www.javapractices.com/topic/TopicAction.do?Id=1你现在可以这样做(一个非常常见的做法):
enum Quark {
/*
* These are called "enum constants".
* An enum type has no instances other than those defined by its
* enum constants. They are implicitly "public static final".
* Each enum constant corresponds to a call to a constructor.
* When no args follow an enum constant, then the no-argument constructor
* is used to create the corresponding object.
*/
UP,
DOWN,
CHARM,
STRANGE,
BOTTOM,
TOP
}
或者你可以这样做:
/**
* Example 2 - adding a constructor to an enum.
*
* If no constructor is added, then the usual default constructor
* is created by the system, and declarations of the
* enum constants will correspond to calling this default constructor.
*/
public enum Lepton {
//each constant implicity calls a constructor :
ELECTRON(-1, 1.0E-31),
NEUTRINO(0, 0.0);
/*
* This constructor is private.
* Legal to declare a non-private constructor, but not legal
* to use such a constructor outside the enum.
* Can never use "new" with any enum, even inside the enum
* class itself.
*/
private Lepton(int aCharge, double aMass){
//cannot call super ctor here
//calls to "this" ctors allowed
fCharge = aCharge;
fMass = aMass;
}
final int getCharge() {
return fCharge;
}
final double getMass() {
return fMass;
}
private final int fCharge;
private final double fMass;
}
以下是官方文档:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html
为什么不这样简单:
public enum Animal {
CAT(4), RAT(4), BAT(4), CHICKEN(2), ..., ANT(6), SPIDER(8);
// A simple attribute, like any other java class.
// Final to ensure it will never change.
private final int legs;
// Note that this constructor is private.
private Animal(int legs) {
this.legs = legs;
}
// A method, like any other class.
public int getLegs() {
return legs;
}
}
使用它:
// How to get all the animals in the enum.
Animal[] animals = Animal.values();
// How to get the number of animals.
int numAnimals = animals.length;
// How to get the number of legs of some animal.
int howManyLegsHaveTheAnt = Animal.ANT.getLegs();
int howManyLegsHaveTheFirstAnimal = animals[0].getLegs();
// How to get the name of a given animal.
String theFirstAnimalName = animals[0].name(); // Will return "CAT".
// How to get the position in the enum of some animal.
int antPositionInTheEnum = Animal.ANT.ordinal();
// How to get an animal given its name.
Animal rat = Enum.valueOf(Animal.class, "RAT");
Animal someAnimal = Enum.valueOf(Animal.class, animalName);
简单的回答:不,Java没有类似c的枚举。虽然在java中也可以通过下面的一系列语句来实现:
public static final int GREEN = 1;
public static final int RED = 2;
public static final int BLUE = 3;
Java枚举是不同的
在您的情况下,使用枚举不是一个好主意。枚举本质上是不可变的东西,是一个固定的集合,在这个集合中不能产生新的元素,也不能破坏现有的元素。工作日、月份和纸牌套装都是枚举的好例子,现有的集合是固定不变的,永远不会创建新元素,也不会破坏现有元素。动物类型、音乐类型、贴图设置等都不遵循这些规则。
最好的方法是最明显的:定义一个接口或抽象类Animal。并将所有动物类型定义为一个亚型。
开关和goto一样邪恶,它们很简单,很容易使用,看起来很无辜,但最终会把你的代码转换成意大利面条丛林。不要使用您想要的开关,而是使用多态性。即:
// Don't:
public class SomeClass {
public void myMethod() {
switch (animal.id) {
case TYPE_CAT:
doSomethingThatCatDoes();
doSomethingElse();
anotherThing();
break;
case TYPE_DOG:
bark();
doSomethingThatDogDoes();
otherThing();
break;
}
}
}
// Do:
public interface Animal {
public void myMethodAction();
// Other methods.
}
public class Cat implements Animal {
@Override
public void myMethodAction() {
doSomethingThatCatDoes();
doSomethingElse();
anotherThing();
}
}
public class Dog implements Animal {
@Override
public void myMethodAction() {
bark();
doSomethingThatDogDoes();
otherThing();
}
}
public class SomeClass {
public void myMethod() {
animal.myMethodAction();
}
}
当您这样做时,代码往往会变得更大,但这并不意味着更复杂。相反,它变得更好地组织,因为SomeClass不再需要知道确切的动物类型,每种动物类型的特定逻辑都在一个地方,如果您需要改变动物的行为,您不需要搜索和改变很多非常遥远的地方。此外,添加新的动物类型变得更加容易。正如你应该看到的,你的项目变得更加灵活,以适应未来的变化(也就是说,更容易改变,更难破坏)。
您应该注意到我没有使用显式id。避免id,因为它们是邪恶的,你已经有了它们的隐含意义。每个对象都有一个唯一的内存地址,这个内存地址就是id。那么public int mType;
场就变成了public Class<? extends Animal> mType;
场。如果您确实需要这些id,请尽量缩短它们的使用时间,并且尽量少使用它们。这样做的原因是为了更好地使用OO(我将在下面解释)。
另外,你的TypeInfo只是一堆公共属性。求你了,千万千万千万别想这么做。在OO中,公共属性就像goto和switch一样令人讨厌,它们肯定会以100%的概率破坏你的项目。相反,无论你做什么需要处理字段,都要放入TypeInfo类并将字段设为私有。这并不意味着用无脑的getter和setter来替换公共属性,而是把你的业务逻辑放在那里。
我强烈建议你深入学习一些OO。特别是真正的封装(有些人说添加一堆脑残的getter和setter是可以的,但事实并非如此,这不是真正的封装)。研究多态性,不仅仅是它是什么以及它是如何工作的,而是如何使用它以及为什么使用它。最重要的是,学习内聚和耦合,使类有意义,相当独立,可重用和灵活。
- 不带大括号的枚举形式
- 枚举环境变量的惯用C++14/C++17方法
- 类似枚举的计算常量
- 如何正确实现和访问运算符的各种自定义枚举器
- 错误:从"int"到枚举c++的转换无效
- C++中构造函数中的枚举
- 访问在 C++ 结构中声明的枚举变量
- 枚举类'classname'的多重定义
- C++ 中的 Java 样式枚举
- Java 类型的枚举,C++中的自定义值和构造函数
- 自动为枚举添加类似 Java 枚举的功能
- 在C++中模拟Java枚举
- 如何在类似java的c++中迭代器枚举
- 如何使用类似 Java 的 C++ 枚举作为另一个类的成员变量
- 如何从C++JNI中获取Java枚举
- Java中的类c枚举
- 在c++和Java之间共享定义或枚举
- 如何在SWIG Java目标中包装对枚举的所有引用
- 如何在JAVA (Android NDK)中访问.h中声明的枚举
- 在c++中等价于Java中枚举的.values()