Cách chính xác để truyền Int cho enum trong Java được đưa ra enum sau đây là gì?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Cách chính xác để truyền Int cho enum trong Java được đưa ra enum sau đây là gì?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Câu trả lời:
Hãy thử MyEnum.values()[x]
nơi x
phải 0
hoặc 1
, tức là một thứ tự hợp lệ cho enum đó.
Lưu ý rằng trong enum Java thực sự là các lớp (và các giá trị enum là các đối tượng) và do đó bạn không thể truyền một int
hoặc thậm chí Integer
cho một enum.
MyEnum.values()
vì nó đắt tiền. tức là nếu bạn gọi nó hàng trăm lần.
MyEnum.values()[x]
là một hoạt động đắt tiền. Nếu hiệu suất là một mối quan tâm, bạn có thể muốn làm một cái gì đó như thế này:
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]
là một hoạt động đắt tiền. Tôi không biết làm thế nào nó hoạt động chi tiết, nhưng với tôi có vẻ như việc truy cập một phần tử trong Mảng sẽ không phải là vấn đề lớn, hay còn gọi là thời gian không đổi. Nếu mảng phải được xây dựng thì phải mất thời gian O (n), đó là thời gian chạy giống như giải pháp của bạn.
values()
tạo ra một mảng mới mỗi lần, bởi vì các mảng có thể thay đổi được nên sẽ không an toàn khi trả về cùng một lần nhiều lần. Các câu lệnh chuyển đổi không nhất thiết phải là O (n), chúng có thể được biên dịch thành các bảng nhảy. Vì vậy, tuyên bố của Lorenzo có vẻ hợp lý.
myEnum = myEnumValues[i]
vẫn sẽ trả lại i
mục thứ trong Enum mà không thay đổi.
Nếu bạn muốn đưa ra các giá trị số nguyên của mình, bạn có thể sử dụng cấu trúc như bên dưới
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;
}
}
Bạn có thể thử như thế này.
Tạo Class với id phần tử.
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;
}
}
Bây giờ Lấy Enum này bằng id dưới dạng int.
MyEnum myEnum = MyEnum.fromId(5);
Tôi lưu trữ các giá trị và tạo một phương thức truy cập tĩnh đơn giản:
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
cùng tên với phương thức values()
. Tôi sử dụng cachedValues
cho tên trường.
Các enum Java không có cùng kiểu ánh xạ enum-int như chúng làm trong C ++.
Điều đó nói rằng, tất cả các values
enum đều có một phương thức trả về một mảng các giá trị enum có thể, vì vậy
MyEnum enumValue = MyEnum.values()[x];
nên làm việc. Hơi khó chịu một chút và tốt hơn hết là đừng thử và chuyển đổi từ int
s sang Enum
s (hoặc ngược lại) nếu có thể.
Đây không phải là điều thường được thực hiện, vì vậy tôi sẽ xem xét lại. Nhưng có nói rằng, các hoạt động cơ bản là: int -> enum bằng EnumType.values () [intNum] và enum -> int bằng enumInst.ordinal ().
Tuy nhiên, vì mọi cách triển khai các giá trị () không có lựa chọn nào khác ngoài việc cung cấp cho bạn một bản sao của mảng (mảng java không bao giờ chỉ đọc), bạn sẽ được phục vụ tốt hơn bằng cách sử dụng EnumMap để lưu trữ enum -> int maps.
Đây là giải pháp tôi dự định đi cùng. Điều này không chỉ hoạt động với các số nguyên không tuần tự, mà nó còn hoạt động với bất kỳ loại dữ liệu nào khác mà bạn có thể muốn sử dụng làm id cơ bản cho các giá trị enum của mình.
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;
}
}
Tôi chỉ cần chuyển đổi id thành enums vào những thời điểm cụ thể (khi tải dữ liệu từ một tệp), vì vậy không có lý do gì để tôi giữ Bản đồ trong bộ nhớ mọi lúc. Nếu bạn cần bản đồ có thể truy cập mọi lúc, bạn luôn có thể lưu trữ nó dưới dạng thành viên tĩnh của lớp Enum.
clearCachedValues
khi bạn sử dụng xong (đặt trường riêng trở lại null). Tôi xem xét MyEnum.fromInt(i)
dễ hiểu hơn là đi vòng quanh một đối tượng bản đồ.
Trong trường hợp nó giúp người khác, tùy chọn tôi thích, không được liệt kê ở đây, sử dụng chức năng Bản đồ của 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);
}
}
Với mặc định bạn có thể sử dụng null
, bạn có thể throw IllegalArgumentException
hoặc bạn fromInt
có thể trả lại Optional
bất kỳ hành vi nào bạn thích.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
phương pháp cũng.
Bạn có thể lặp lại values()
enum và so sánh giá trị nguyên của enum với id
như dưới đây:
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
}
}
Và sử dụng như thế này:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Tôi hy vọng điều này sẽ giúp;)
Dựa trên câu trả lời của @ChadBefus và bình luận @shmosel, tôi khuyên bạn nên sử dụng câu trả lời này. (Tra cứu hiệu quả và hoạt động trên java thuần túy> = 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());
}
}
Một tùy chọn tốt là tránh chuyển đổi từ int
sang enum
: ví dụ: nếu bạn cần giá trị tối đa, bạn có thể so sánh x.ordinal () với y.ordinal () và trả lại x hoặc y tương ứng. (Bạn có thể cần phải sắp xếp lại các giá trị của mình để làm cho sự so sánh đó có ý nghĩa.)
Nếu điều đó là không thể, tôi sẽ lưu trữ MyEnum.values()
vào một mảng tĩnh.
Đây là câu trả lời giống như các bác sĩ nhưng nó cho thấy làm thế nào để loại bỏ vấn đề với các mảng có thể thay đổi. Nếu bạn sử dụng cách tiếp cận này vì dự đoán nhánh trước sẽ có hiệu ứng rất ít đến không và toàn bộ mã chỉ gọi hàm giá trị mảng () có thể thay đổi chỉ một lần. Vì cả hai biến đều tĩnh nên chúng sẽ không tiêu thụ bộ nhớ n * cho mỗi lần sử dụng phép liệt kê này.
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;
}
}
}
Trong 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]
}
}
Sử dụng:
val status = Status.getStatus(1)!!
Đã viết thực hiện này. Nó cho phép thiếu các giá trị, giá trị âm và giữ mã nhất quán. Bản đồ được lưu trữ là tốt. Sử dụng một giao diện và cần 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);
}
}
Giao diện
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;
}
}