2013-04-25 9 views
7

Chciałbym mieć klasę, która emuluje EnumMap, ale przechowuje wartości int zamiast jakiegoś obiektu. Teraz możesz oczywiście stworzyć mapę EnumMap, która mapuje do liczb całkowitych, ale to dużo autoboxingu, którego chciałbym uniknąć, jeśli to możliwe.Dostęp do metod .values ​​() i .ordinal() arbitralnego wyliczenia?

Więc chciałbym klasę tak:

public class EnumIntAttributeMap 
{ 
    enum Attribute 
    { 
     Height, Weight; 
    } 

    private final int[] values; 

    public EnumIntAttributeMap() 
    { 
     this.values = new int[Attribute.values().length]; 
    } 

    public int getValue(Attribute a) 
    { 
     return this.values[a.ordinal()]; 
    } 

    public void setValue(Attribute a, int value) 
    { 
     this.values[a.ordinal()] = value; 
    } 
} 

wyjątkiem Chciałbym zrobić wersję, która jest nazwą rodzajową we wszystkich teksty stałe. Teraz, ponieważ metody .values ​​() i .ordinal() są domyślnie dodawane przez kompilator, wydaje się, że jedynym sposobem uzyskania do nich dostępu byłaby refleksja, która pochłonęłaby wzrost wydajności, który próbuję osiągnąć, unikając auto-boxing, ale może jest coś, czego mi brakuje.

Jakieś myśli?

EDIT:

Myślę, że moje początkowe pytanie było jasne. Chciałbym klasy, która bierze (jako parametr ogólny) wyliczenie, a następnie może korzystać z tych samych operacji.

Mogę więc używać go z dowolnym wyliczeniem, bez potrzeby pisania zajęć dla każdego rodzaju wyliczenia za każdym razem. Takich jak:

enum Attribute { Height, Weight } 

enum AbilityScore {Str, Dex, Con, Int, Wis, Cha} 

IdealClass<Attribute> attributeVersion; 

IdealClass<AbilityScore> abilityScoreVersion; 

i tak dalej.

+0

Jeśli 'wartości int' są małe, czyli w pamięci podręcznej, to nie będzie żadnej różnicy (BTW można zwiększyć rozmiar pamięci podręcznej) Jednakże, jeśli int wartości są duże, może to wartość, którą część pamięci/Śmieci. –

+0

Widziałem, że można rozszerzyć pamięć podręczną Integer za pomocą argumentu wiersza poleceń. Czy jest jakiś sposób, aby to zrobić po uruchomieniu programu z poziomu programu? – Lokathor

Odpowiedz

9

to rozwiązanie:

public class EnumIntMap<E extends Enum<E>> { 

    private final int[] values; 

    public EnumIntMap(Class<E> cls) 
    { 
     this.values = new int[cls.getEnumConstants().length]; 
    } 

    public int getValue(E a) 
    { 
     return this.values[a.ordinal()]; 
    } 

    public void setValue(E a, int value) 
    { 
     this.values[a.ordinal()] = value; 
    } 
} 

Będziesz musiał zainicjować mapę także z klasą wyliczenia.

enum Attribute { Height, Weight } 

enum AbilityScore {Str, Dex, Con, Int, Wis, Cha} 

EnumIntMap<Attribute> attributeVersion = new EnumIntMap(Attribute.class); 

EnumIntMap<AbilityScore> abilityScoreVersion = new EnumIntMap(AbilityScore.class); 
+0

Och tak Tak to robisz .. Próbowałem zrobić getDeclaringClass() i inne dziwactwa i właśnie uderzałem moją głowę o ścianę. Śliczny. Maba, jesteś dzisiaj moją ulubioną osobą. – Lokathor

+0

@Lokathor Dzięki :-) – maba

0

Przeczytaj to: Oracle's Doc on Enums.

Myślę, że można zrobić coś, co jest podobny do przykładu planety:

public enum YourEnum{ 
    HEIGHT (0), 
    WIDTH (1); 

    private final int index; 

    YourEnum(int index) { 
     this.index = index; 
    } 
    public int index() { return index; } 
} 
0

To co ja osobiście używać i daje mi piękny normalizacji w API

Common Interface:

public interface IValueEnum<T> {  
    T value(); 
} 

Enum implementuje go w następujący sposób:

public enum MyEnum implements IValueEnum<Integer> { 
    WIDTH(1), 
    HEIGHT(2); 

    private final int value; 
    MyEnum(int value) { this.value = value; } 

    @Override 
    public Integer value() { 
     return value; 
    } 
} 

Teraz możesz uzyskać ostateczną wartość, przechodząc przez MyEnum.WIDTH.value(), itp. Ponieważ używa generycznych innych wyrażeń, może użyć Longs lub String lub co masz. Pozwala na posiadanie jednego prostego interfejsu opartego na Enum w aplikacji. Pozwala również być całkowicie generycznych w mapy, itp

EDIT: Na podstawie Nowego przykładu

public class IdealClass<T extends Enum> { 

    T enumValue; 

    public IdealClass() { 
    } 

} 
+0

Używam już liczby porządkowej enum jako indeksu, chciałbym móc to zrobić dla więcej niż jednego rodzaju wyliczenia z tą samą klasą. – Lokathor

+0

@Lokathor dobrze z tym podejściem, można dodać metodę do interfejsu o nazwie getIndex(), a następnie można użyć IValueEnum jako typ rodzajowy ... nie? – Ixx

+0

@Ixx Ty ... mógłbyś? ale jest to praktycznie przeciwieństwo tego, co chciałem. Zamiast regulowanej mapy, która pozwala mapować wartości Enum na ints, po prostu otrzymujesz kilka statycznych ostatecznych globali. – Lokathor

1

Wszystko java Enum dorozumiany przedłużyć java.lang.Enum, więc myślę, że to, czego szukasz jest:

public class EnumIntAttributeMap<E extends java.lang.Enum<E>> { 
    // [...] 
} 
+0

Ale to tylko daje ci E, którego nie możesz potem wywołać .values ​​() w konstruktorze, aby ustawić długość tablicy. – Lokathor

+0

Masz rację! Odpowiedź Maby na to odpowiedź :) – ValarDohaeris

2

Kluczem do tego genetycznie wiedząc rodzajową związaną z wyliczenia:

<T extends Enum<T>> 

Twoja klasa może pracować dla żadnego enum następująco:

public class EnumIntAttributeMap<T extends Enum<T>> { 
    private final int[] values; 
    private final Class<T> clazz; 

    public EnumIntAttributeMap(Class<T> clazz) { 
     this.clazz = clazz; 
     this.values = new int[clazz.getEnumConstants().length]; 
    } 

    public int getValue(T a) { 
     return this.values[a.ordinal()]; 
    } 

    public void setValue(T a, int value) { 
     this.values[a.ordinal()] = value; 
    } 
} 

Należy pamiętać, że Konstruktor wymaga tokena typu , który jest wymagany z powodu wymazywania typu środowiska wykonawczego Java.

Powiązane problemy