Apa cara yang benar untuk melemparkan Int ke enum di Jawa mengingat enum berikut?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Apa cara yang benar untuk melemparkan Int ke enum di Jawa mengingat enum berikut?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Jawaban:
Coba di MyEnum.values()[x]
mana x
harus 0
atau 1
, yaitu ordinal yang valid untuk enum itu.
Perhatikan bahwa dalam Java enum sebenarnya adalah kelas (dan nilai enum dengan demikian adalah objek) dan dengan demikian Anda tidak dapat melemparkan int
atau bahkan Integer
ke enum.
MyEnum.values()
karena harganya mahal. yaitu jika Anda menyebutnya ratusan kali.
MyEnum.values()[x]
adalah operasi yang mahal. Jika kinerjanya mengkhawatirkan, Anda mungkin ingin melakukan sesuatu seperti ini:
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]
sebagai operasi yang mahal. Saya tidak tahu cara kerjanya secara detail, tetapi bagi saya sepertinya mengakses elemen dalam Array bukan masalah besar, alias waktu yang konstan. Jika array harus dibangun, dibutuhkan O (n) waktu, yang merupakan waktu runnning yang sama dengan solusi Anda.
values()
menghasilkan array baru setiap kali, karena array bisa berubah sehingga tidak aman untuk mengembalikan yang sama beberapa kali. Beralih pernyataan tidak harus O (n), mereka dapat dikompilasi ke tabel lompatan. Jadi klaim Lorenzo tampaknya bisa dibenarkan.
myEnum = myEnumValues[i]
masih akan mengembalikan i
item th di Enum tanpa perubahan.
Jika Anda ingin memberikan nilai integer Anda, Anda dapat menggunakan struktur seperti di bawah ini
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;
}
}
Anda bisa coba seperti ini.
Buat Kelas dengan id elemen.
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;
}
}
Sekarang Ambil Enum ini menggunakan id sebagai int.
MyEnum myEnum = MyEnum.fromId(5);
Saya menyimpan nilai-nilai dan membuat metode akses statis sederhana:
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
nama yang sama dengan metode values()
. Saya menggunakan cachedValues
untuk nama bidang.
Java enum tidak memiliki pemetaan enum-ke-int yang sama dengan yang mereka lakukan di C ++.
Yang mengatakan, semua enum memiliki values
metode yang mengembalikan array nilai enum yang mungkin, jadi
MyEnum enumValue = MyEnum.values()[x];
harus bekerja. Agak jahat dan mungkin lebih baik untuk tidak mencoba dan mengkonversi dari int
s ke Enum
s (atau sebaliknya) jika memungkinkan.
Ini bukan sesuatu yang biasanya dilakukan, jadi saya akan mempertimbangkan kembali. Tetapi setelah mengatakan itu, operasi mendasar adalah: int -> enum menggunakan EnumType.values () [intNum], dan enum -> int menggunakan enumInst.ordinal ().
Namun, karena implementasi nilai apa pun () tidak punya pilihan selain memberi Anda salinan array (array java tidak pernah hanya baca), Anda akan lebih baik dilayani menggunakan EnumMap untuk cache pemetaan enum -> int.
Inilah solusi yang saya rencanakan. Ini tidak hanya berfungsi dengan integer non-sekuensial, tetapi juga dapat bekerja dengan tipe data lain yang mungkin ingin Anda gunakan sebagai id yang mendasari nilai enum Anda.
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;
}
}
Saya hanya perlu mengonversi id ke enum pada waktu tertentu (saat memuat data dari file), jadi tidak ada alasan bagi saya untuk menyimpan Peta di memori setiap saat. Jika Anda benar-benar membutuhkan peta agar dapat diakses setiap saat, Anda dapat selalu menyimpannya sebagai anggota statis kelas Enum Anda.
clearCachedValues
ketika Anda selesai menggunakannya (yang menetapkan bidang pribadi kembali ke nol). Saya menganggap MyEnum.fromInt(i)
lebih mudah dipahami daripada melewati objek peta.
Jika itu membantu orang lain, opsi yang saya pilih, yang tidak tercantum di sini, menggunakan fungsionalitas Peta 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);
}
}
Dengan default yang dapat Anda gunakan null
, Anda bisa throw IllegalArgumentException
atau Anda fromInt
bisa mengembalikan Optional
, perilaku apa pun yang Anda inginkan.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
metode juga.
Anda dapat beralih lebih values()
dari enum dan membandingkan nilai integer enum dengan yang diberikan id
seperti di bawah ini:
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
}
}
Dan gunakan seperti ini:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Saya harap ini membantu;)
Berdasarkan jawaban @ChadBefus dan komentar @shmosel, saya sarankan menggunakan ini. (Pencarian efisien, dan berfungsi di java murni> = 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());
}
}
Pilihan yang baik adalah menghindari konversi dari int
menjadienum
: misalnya, jika Anda membutuhkan nilai maksimal, Anda dapat membandingkan x.ordinal () ke y.ordinal () dan mengembalikan x atau y secara bersamaan. (Anda mungkin perlu memesan ulang nilai-nilai Anda agar perbandingan tersebut bermakna.)
Jika itu tidak mungkin, saya akan menyimpan MyEnum.values()
ke array statis.
Ini adalah jawaban yang sama dengan dokter tetapi ini menunjukkan bagaimana cara menghilangkan masalah dengan array yang bisa berubah. Jika Anda menggunakan pendekatan semacam ini karena prediksi cabang terlebih dahulu jika akan memiliki efek sangat kecil ke nol dan seluruh kode hanya memanggil nilai array yang dapat diubah () hanya berfungsi sekali. Karena kedua variabel statis, mereka tidak akan menggunakan memori n * untuk setiap penggunaan enumerasi ini juga.
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;
}
}
}
Di 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]
}
}
Pemakaian:
val status = Status.getStatus(1)!!
Tulis implementasi ini. Ini memungkinkan untuk nilai yang hilang, nilai negatif dan menjaga kode konsisten. Peta juga di-cache. Menggunakan antarmuka dan membutuhkan 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);
}
}
Antarmuka
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;
}
}