Aşağıdaki numaralandırma göz önüne alındığında, Java'da bir numaraya Int yerleştirmenin doğru yolu nedir?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Aşağıdaki numaralandırma göz önüne alındığında, Java'da bir numaraya Int yerleştirmenin doğru yolu nedir?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Yanıtlar:
Deneyin MyEnum.values()[x]
nerede x
olmalı 0
ya 1
o enum için geçerli bir sıra, ie.
Java numaralandırmalarında aslında sınıflar (ve dolayısıyla numaralandırma değerleri nesnelerdir) ve dolayısıyla bir numaralandırmaya int
veya hatta Integer
numaralandırmaya izin veremeyeceğinizi unutmayın .
MyEnum.values()
Pahalı olduğu için önbelleklemek isteyebilirsiniz . yani yüzlerce kez diyorsan.
MyEnum.values()[x]
pahalı bir işlemdir. Performans bir endişe kaynağıysa, böyle bir şey yapmak isteyebilirsiniz:
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]
pahalı bir ameliyat olarak gördüğünüzü açıklayabilir misiniz ? Nasıl çalıştığını ayrıntılı olarak bilmiyorum, ama bana göre bir Array'deki bir öğeye erişmek önemli bir şey değil, sabit bir zaman gibi görünüyor. Dizinin oluşturulması gerekiyorsa, çözümünüzle aynı çalışma süresi olan O (n) zamanı alır.
values()
Her seferinde yeni bir dizi oluşturduğunu varsayıyorum , çünkü diziler değiştirilebilir, bu yüzden aynı diziyi birden çok kez döndürmek güvenli olmazdı. Anahtar ifadeleri mutlaka O (n) değildir, tabloları atlamak için derlenebilirler. Yani Lorenzo'nun iddiaları haklı görünüyor.
myEnum = myEnumValues[i]
yine de değiştirmeden döndürür i
.
Tamsayı değerlerinizi vermek istiyorsanız, aşağıdaki gibi bir yapı kullanabilirsiniz
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;
}
}
Bunu deneyebilirsin.
Öğe kimliğiyle Sınıf oluşturun.
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;
}
}
Şimdi int olarak id kullanarak bu Numaralamayı getir.
MyEnum myEnum = MyEnum.fromId(5);
Ben değerleri önbellek ve basit bir statik erişim yöntemi oluşturmak:
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
yöntemle aynı adı vermezseniz daha az kafa karıştırıcıdır values()
. cachedValues
Alan adı için kullanıyorum .
Java numaralandırmalarında, C ++ ile aynı numaralandırma-int eşlemesi yoktur.
Bununla birlikte, tüm values
numaralandırmaların bir dizi olası numaralandırma değeri döndüren bir yöntemi vardır,
MyEnum enumValue = MyEnum.values()[x];
çalışmalı. Biraz pis ve o denemek ve dönüştürürler değil daha iyi olabilir int
için s Enum
mümkünse (tersi veya yardımcısı) s.
Bu genellikle yapılan bir şey değil, bu yüzden tekrar düşünürdüm. Ancak bunu söyledikten sonra, temel işlemler şunlardır: EnumType.values () [intNum] kullanarak int -> enum ve enumInst.ordinal () kullanarak enum -> int.
Ancak, değerlerin () herhangi bir uygulamasının size dizinin bir kopyasını vermekten başka seçeneği olmadığı için (java dizileri hiçbir zaman salt okunur değildir), enum -> int eşlemesini önbelleğe almak için bir EnumMap kullanarak daha iyi sunulur.
İşte planladığım çözüm. Bu yalnızca sıralı olmayan tamsayılarla çalışmaz, aynı zamanda numaralandırma değerleriniz için temel kimlik olarak kullanmak isteyebileceğiniz diğer veri türleriyle de çalışmalıdır.
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;
}
}
Ben sadece bir dosyadan veri yüklerken kimlikleri belirli zamanlarda numaralarını dönüştürmek gerekir, bu yüzden Harita her zaman bellekte tutmak için hiçbir neden yoktur. Haritanın her zaman erişilebilir olması gerekiyorsa, haritayı her zaman Enum sınıfınızın statik bir üyesi olarak önbelleğe alabilirsiniz.
clearCachedValues
(özel alanı null değerine geri ayarlar) kullandığınızda ikinci bir yöntem ekleyin . Ben düşünün MyEnum.fromInt(i)
bir harita nesnesi etrafında geçen daha anlamak daha kolay.
Başkalarına yardımcı olması durumunda, burada listelenmeyen tercih ettiğim seçenek Guava'nın Haritalar işlevini kullanır :
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);
}
}
Varsayılan ile kullanabilirsiniz null
yapabilirsiniz, throw IllegalArgumentException
veya senin fromInt
bir geri dönebilirler Optional
Tercih ettiğiniz herhangi davranış.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
yöntem de tanımlamak isteyebilir .
values()
Enum üzerinde yineleme yapabilir ve enum'un tamsayı değerini id
aşağıdaki gibi verebilirsiniz :
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
}
}
Ve aynen böyle kullanın:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Umarım bu yardımcı olur;)
@ChadBefus'un cevabına ve @shmosel yorumuna dayanarak bunu kullanmanızı tavsiye ederim. (Verimli arama ve saf java üzerinde çalışır> = 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());
}
}
İyi bir seçenek olan önlemek dönüşüm int
için enum
: Eğer azami değer gerekirse, örneğin, sen x.ordinal karşılaştırabilirsiniz () y.ordinal () ve geri dönüş x veya y uygun. (Bu karşılaştırmayı anlamlı hale getirmek için değerlerinizi yeniden sıralamanız gerekebilir.)
Bu mümkün değilse, MyEnum.values()
statik bir dizi saklamak istiyorum .
Bu, doktorlarla aynı cevaptır, ancak değişebilir dizilerdeki sorunun nasıl ortadan kaldırılacağını gösterir. Şube tahmininden dolayı bu tür bir yaklaşımı kullanırsanız, ilk önce çok azdan sıfıra etkisi olur ve tüm kod yalnızca bir kez değişebilir dizi değerleri () işlevini çağırır. Her iki değişken de statik olduğundan, bu numaralandırmanın her kullanımı için n * bellek tüketmezler.
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'de:
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]
}
}
Kullanımı:
val status = Status.getStatus(1)!!
Bu uygulamayı yazdı. Eksik değerlere, negatif değerlere izin verir ve kodu tutarlı tutar. Harita da önbelleğe alınır. Bir arayüz kullanır ve Java 8 gerektirir.
Sıralama
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);
}
}
Arayüz
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;
}
}