วิธีที่ถูกต้องในการส่ง Int ไปยัง enum ใน Java จะให้ enum ต่อไปนี้คืออะไร?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
วิธีที่ถูกต้องในการส่ง Int ไปยัง enum ใน Java จะให้ enum ต่อไปนี้คืออะไร?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
คำตอบ:
ลองดูMyEnum.values()[x]
ว่าx
จะต้องอยู่ที่ไหน0
หรือ1
คือเลขที่ถูกต้องสำหรับ enum นั้น
โปรดทราบว่าใน Java enums จริง ๆ แล้วเป็นคลาส (และค่า enum จึงเป็นวัตถุ) และทำให้คุณไม่สามารถส่งint
หรือแม้กระทั่งInteger
กับ enum
MyEnum.values()
เนื่องจากมีราคาแพง เช่นถ้าคุณเรียกมันว่าหลายร้อยครั้ง
MyEnum.values()[x]
เป็นการดำเนินการที่มีราคาแพง หากประสิทธิภาพเป็นกังวลคุณอาจต้องการทำสิ่งนี้:
public enum MyEnum {
EnumValue1,
EnumValue2;
public static MyEnum fromInteger(int x) {
switch(x) {
case 0:
return EnumValue1;
case 1:
return EnumValue2;
}
return null;
}
}
MyEnum.values()[x]
ว่าการทำงานมีราคาแพง ฉันไม่รู้ว่ามันทำงานอย่างไรในรายละเอียด แต่สำหรับฉันแล้วดูเหมือนว่าการเข้าถึงองค์ประกอบในอาเรย์จะไม่ใช่เรื่องใหญ่อะไรเวลาคงที่ หากอาร์เรย์ต้องมีการสร้างจะต้องใช้เวลา O (n) ซึ่งเป็นเวลาเดียวกับการแก้ปัญหาของคุณ
values()
มีการสร้างอาร์เรย์ใหม่ทุกครั้งเนื่องจากอาร์เรย์มีการเปลี่ยนแปลงดังนั้นจึงไม่ปลอดภัยที่จะส่งคืนค่าเดียวกันหลาย ๆ ครั้ง คำสั่ง Switch ไม่จำเป็นต้องเป็น O (n) สามารถรวบรวมเพื่อข้ามตารางได้ ดังนั้นคำกล่าวอ้างของ Lorenzo จึงดูเป็นธรรม
myEnum = myEnumValues[i]
จะยังคงส่งคืนi
รายการที่ th ใน Enum โดยไม่มีการเปลี่ยนแปลง
หากคุณต้องการให้ค่าจำนวนเต็มของคุณคุณสามารถใช้โครงสร้างเช่นด้านล่าง
public enum A
{
B(0),
C(10),
None(11);
int id;
private A(int i){id = i;}
public int GetID(){return id;}
public boolean IsEmpty(){return this.equals(A.None);}
public boolean Compare(int i){return id == i;}
public static A GetValue(int _id)
{
A[] As = A.values();
for(int i = 0; i < As.length; i++)
{
if(As[i].Compare(_id))
return As[i];
}
return A.None;
}
}
คุณสามารถลองสิ่งนี้
สร้างคลาสด้วยรหัสองค์ประกอบ
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public static MyEnum fromId(int id) {
for (MyEnum type : values()) {
if (type.getId() == id) {
return type;
}
}
return null;
}
}
ตอนนี้ดึง Enum นี้โดยใช้ id เป็น int
MyEnum myEnum = MyEnum.fromId(5);
ฉันแคชค่าและสร้างวิธีการเข้าถึงแบบคงที่แบบง่าย:
public static enum EnumAttributeType {
ENUM_1,
ENUM_2;
private static EnumAttributeType[] values = null;
public static EnumAttributeType fromInt(int i) {
if(EnumAttributeType.values == null) {
EnumAttributeType.values = EnumAttributeType.values();
}
return EnumAttributeType.values[i];
}
}
values
values()
ฉันใช้cachedValues
สำหรับชื่อฟิลด์
Java enums ไม่มีการแม็พ enum-to-int แบบเดียวกับที่ทำใน C ++
ที่กล่าวว่า enums ทั้งหมดมีvalues
วิธีที่ส่งกลับอาร์เรย์ของค่า enum ที่เป็นไปได้ดังนั้น
MyEnum enumValue = MyEnum.values()[x];
ควรทำงาน. มันน่ารังเกียจนิดหน่อยและมันอาจเป็นการดีกว่าถ้าไม่ลองและแปลงจากint
s เป็นEnum
s (หรือกลับกัน) ถ้าเป็นไปได้
นี่ไม่ใช่สิ่งที่มักจะทำดังนั้นฉันจะพิจารณาอีกครั้ง แต่ต้องบอกว่าการดำเนินการพื้นฐานคือ: int -> enum โดยใช้ EnumType.values () [intNum] และ enum -> int โดยใช้ enumInst.ordinal ()
อย่างไรก็ตามเนื่องจากการใช้งานค่าใด ๆ () ไม่มีทางเลือกนอกจากให้สำเนาของอาร์เรย์ (java array ไม่เคยอ่านอย่างเดียว) คุณจะได้รับการบริการที่ดีขึ้นโดยใช้ EnumMap เพื่อแคชการแม็ป enum -> int
ใช้ MyEnum enumValue = MyEnum.values()[x];
นี่คือทางออกที่ฉันวางแผนจะไปด้วย ไม่เพียงทำงานกับเลขจำนวนเต็มแบบไม่ต่อเนื่องเท่านั้น แต่ควรทำงานกับชนิดข้อมูลอื่น ๆ ที่คุณอาจต้องการใช้เป็น id พื้นฐานสำหรับค่า enum ของคุณ
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static Map<Integer, MyEnum> buildMap() {
Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>();
MyEnum[] values = MyEnum.values();
for (MyEnum value : values) {
map.put(value.getId(), value);
}
return map;
}
}
ฉันต้องแปลง id เป็น enums ตามเวลาที่กำหนดเท่านั้น (เมื่อโหลดข้อมูลจากไฟล์) ดังนั้นจึงไม่มีเหตุผลที่ฉันจะเก็บแผนที่ไว้ในหน่วยความจำตลอดเวลา หากคุณต้องการให้แผนที่สามารถเข้าถึงได้ตลอดเวลาคุณสามารถแคชในฐานะสมาชิกแบบคงที่ของคลาส Enum ของคุณ
clearCachedValues
เมื่อคุณใช้งานเสร็จแล้ว (ตั้งค่าฟิลด์ส่วนตัวกลับเป็นโมฆะ) ฉันคิดว่าMyEnum.fromInt(i)
เข้าใจง่ายกว่าผ่านวัตถุแผนที่
ในกรณีที่ช่วยเหลือผู้อื่นตัวเลือกที่ฉันชอบซึ่งไม่ได้อยู่ในรายการนี้จะใช้ฟังก์ชั่นแผนที่ของ Guava :
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static ImmutableMap<Integer, MyEnum> reverseLookup =
Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue);
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
}
ด้วยค่าเริ่มต้นที่คุณสามารถใช้null
คุณสามารถthrow IllegalArgumentException
หรือคุณfromInt
สามารถคืนค่าOptional
พฤติกรรมที่คุณต้องการ
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
วิธีการด้วย
คุณสามารถวนซ้ำvalues()
enum และเปรียบเทียบค่าจำนวนเต็มของ enum ได้id
ดังนี้:
public enum TestEnum {
None(0),
Value1(1),
Value2(2),
Value3(3),
Value4(4),
Value5(5);
private final int value;
private TestEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static TestEnum getEnum(int value){
for (TestEnum e:TestEnum.values()) {
if(e.getValue() == value)
return e;
}
return TestEnum.None;//For values out of enum scope
}
}
และใช้แบบนี้:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
ฉันหวังว่านี่จะช่วยได้;)
จากคำตอบของ @ChadBefus และความคิดเห็น @shmosel ฉันขอแนะนำให้ใช้สิ่งนี้ (การค้นหาที่มีประสิทธิภาพและทำงานบน pure java> = 8)
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Arrays;
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static Map<Integer, MyEnum> reverseLookup =
Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
public static void main(String[] args) {
System.out.println(fromInt(-66).toString());
}
}
ตัวเลือกที่ดีคือหลีกเลี่ยงการแปลงจากint
เป็นenum
: ตัวอย่างเช่นหากคุณต้องการค่าสูงสุดคุณอาจเปรียบเทียบ x.ordinal () กับ y.ordinal () และส่งคืน x หรือ y ตามลำดับ (คุณอาจจำเป็นต้องสั่งซื้อใหม่อีกครั้งเพื่อให้การเปรียบเทียบมีความหมาย)
หากเป็นไปไม่ได้ฉันจะเก็บไว้MyEnum.values()
ในอาร์เรย์คงที่
นี่เป็นคำตอบเดียวกับแพทย์ แต่มันแสดงวิธีกำจัดปัญหาด้วยอาร์เรย์ที่ไม่แน่นอน หากคุณใช้วิธีการนี้เนื่องจากการคาดคะเนสาขาก่อนหากจะมีผลกระทบน้อยมากถึงศูนย์และรหัสทั้งหมดจะเรียกเฉพาะค่าอาร์เรย์ที่ไม่แน่นอน () ฟังก์ชั่นเพียงครั้งเดียว เนื่องจากตัวแปรทั้งสองเป็นแบบสแตติกพวกเขาจะไม่ใช้หน่วยความจำ n * สำหรับการใช้การแจงนับนี้ทุกครั้ง
private static boolean arrayCreated = false;
private static RFMsgType[] ArrayOfValues;
public static RFMsgType GetMsgTypeFromValue(int MessageID) {
if (arrayCreated == false) {
ArrayOfValues = RFMsgType.values();
}
for (int i = 0; i < ArrayOfValues.length; i++) {
if (ArrayOfValues[i].MessageIDValue == MessageID) {
return ArrayOfValues[i];
}
}
return RFMsgType.UNKNOWN;
}
enum MyEnum {
A(0),
B(1);
private final int value;
private MyEnum(int val) {this.value = value;}
private static final MyEnum[] values = MyEnum.values();//cache for optimization
public static final getMyEnum(int value) {
try {
return values[value];//OOB might get triggered
} catch (ArrayOutOfBoundsException e) {
} finally {
return myDefaultEnumValue;
}
}
}
ใน Kotlin:
enum class Status(val id: Int) {
NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5);
companion object {
private val statuses = Status.values().associateBy(Status::id)
fun getStatus(id: Int): Status? = statuses[id]
}
}
การใช้งาน:
val status = Status.getStatus(1)!!
เขียนการใช้งานนี้ จะช่วยให้ค่าที่หายไปค่าลบและเก็บรหัสสอดคล้อง แผนที่ถูกแคชเช่นกัน ใช้อินเตอร์เฟสและต้องการ Java 8
enum
public enum Command implements OrdinalEnum{
PRINT_FOO(-7),
PRINT_BAR(6),
PRINT_BAZ(4);
private int val;
private Command(int val){
this.val = val;
}
public int getVal(){
return val;
}
private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class);
public static Command from(int i){
return map.get(i);
}
}
อินเตอร์เฟซ
public interface OrdinalEnum{
public int getVal();
@SuppressWarnings("unchecked")
static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){
Map<Integer, E> m = new HashMap<>();
for(Enum<E> e : EnumSet.allOf(clzz))
m.put(((OrdinalEnum)e).getVal(), (E)e);
return m;
}
}