Java'da dizinden Enum Değeri nasıl alınır?


97

Java'da bir numaram var:

public enum Months
{
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}

Enum değerlerine dizine göre erişmek istiyorum, ör.

Months(1) = JAN;
Months(2) = FEB;
...

Bunu nasıl yapacağım?


12
Bilgisayar biliminde, endeksler 1'den değil 0'dan başlar ;-)
fredoverflow

1
İstediğine emin misin? Genel olarak, düşük seviyeli veri yapılarını uygulamak dışında sıraya dokunmamalısınız (ve daha sonra kalıcılık için ad gibi alternatif mekanizmalar kullanın).
Tom Hawtin - tackline

Sabitleri java.util.Calendar sınıfında da kullanabilirdiniz. Ocak - Aralık için 0 - 11 olarak numaralandırılmışlardır. UnDecember (Ay takvimi ile ilgili bir şey) olduğundan 12'ye dikkat edin. Ama merak ediyorum, JRE'de zaten "stok" olarak gelen ay sabitlerinin neden yeniden icat edildiğini merak ediyorum.
Chris Aldrich

2FredOverflow: Kabul ediyorum, yanlış indeksleme kullandım. 2Tom Hawtin: Evet, eminim. Verileri bazı çerçevelerle sürdürüyorum ve enum yerine tamsayı indeksini geri alıyorum. 2Chris Aldrich: Bu sadece gerçek durumla eşleşmeyen sahte bir örnektir.
jk_

Bu arada, Java 8 ve sonraki sürümleri Monthyerleşik bir enum ile birlikte gelir .
Basil Bourque

Yanıtlar:


234

Bunu dene

Months.values()[index]

39
Bunun her seferinde değerler dizisinin bir kopyasını klonlayacağını unutmayın; bu nedenle, bunu performansa duyarlı kodun iç döngüsünde çağırıyorsanız, statik bir kopya oluşturup bunu kullanmak isteyebilirsiniz.
Christopher Barber

1
Kafam karıştı, o zaman neden onun yerine bir dizi kullanmak istemeyeyim?
Anudeep Samaiya

@AnudeepSamaiya, her yerde aylar [1] yerine kodda uygun enum sabitlerini (Months.JAN) kullanmak istiyor olabiliriz.
Harry Joy

@Christopher Barber işte "statik bir kopya yapmak" için tek public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};Months i = ALL.get(index)
satırlık bir program:,

Sadece Months.values ​​(). Clone () kullanmak veya değişkenlik konusunda paranoyak iseniz, onu değişmez bir listeye sarmak için (Koleksiyonlara bakın)
Christopher Barber

20

İşte bunu yapmanın üç yolu.

public enum Months {
    JAN(1), FEB(2), MAR(3), APR(4), MAY(5), JUN(6), JUL(7), AUG(8), SEP(9), OCT(10), NOV(11), DEC(12);


    int monthOrdinal = 0;

    Months(int ord) {
        this.monthOrdinal = ord;
    }

    public static Months byOrdinal2ndWay(int ord) {
        return Months.values()[ord-1]; // less safe
    }

    public static Months byOrdinal(int ord) {
        for (Months m : Months.values()) {
            if (m.monthOrdinal == ord) {
                return m;
            }
        }
        return null;
    }
    public static Months[] MONTHS_INDEXED = new Months[] { null, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

}




import static junit.framework.Assert.assertEquals;

import org.junit.Test;

public class MonthsTest {

@Test
public void test_indexed_access() {
    assertEquals(Months.MONTHS_INDEXED[1], Months.JAN);
    assertEquals(Months.MONTHS_INDEXED[2], Months.FEB);

    assertEquals(Months.byOrdinal(1), Months.JAN);
    assertEquals(Months.byOrdinal(2), Months.FEB);


    assertEquals(Months.byOrdinal2ndWay(1), Months.JAN);
    assertEquals(Months.byOrdinal2ndWay(2), Months.FEB);
}

}

5
public staticdeğiştirilebilir (hem dizi hem de olmayan final). Euw. Ve bir bombayı IllegalArgumentExceptiongeri vermekten çok daha mantıklı null.
Tom Hawtin - tackline

4

Ben de aynısını denedim ve aşağıdaki çözümü buldum:

public enum Countries {
    TEXAS,
    FLORIDA,
    OKLAHOMA,
    KENTUCKY;

    private static Countries[] list = Countries.values();

    public static Countries getCountry(int i) {
        return list[i];
    }

    public static int listGetLastIndex() {
        return list.length - 1;
    }
}

Sınıfın bir dizi içinde kaydedilmiş kendi değerleri vardır ve diziyi indeks pozisyonundaki numaralandırmak için kullanırım. Yukarıda bahsedildiği gibi diziler 0'dan sayılmaya başlar, dizininizin '1'den başlamasını istiyorsanız bu iki yöntemi şu şekilde değiştirmeniz yeterlidir:

public static String getCountry(int i) {
    return list[(i - 1)];
}

public static int listGetLastIndex() {
    return list.length;
}

Ana sayfamın içinde gerekli ülkeleri alıyorum.

public static void main(String[] args) {
   int i = Countries.listGetLastIndex();
   Countries currCountry = Countries.getCountry(i);
}

currCountry'yi son ülke, bu durumda Ülkeler.KENTUCKY olarak ayarlar.

Nesnelerinizi almak için sabit kodlanmış belirteçler kullanıyorsanız, bu kodun ArrayOutOfBoundsExceptions'dan çok etkilendiğini unutmayın.


2

Geçenlerde aynı sorunu yaşadım ve Harry Joy'un sağladığı çözümü kullandım. Bu çözüm yalnızca sıfır tabanlı numaralandırma ile çalışır. Ayrıca, aralık dışı dizinler ile ilgilenmediği için tasarruf etmeyi de düşünmem.

Kullanmaya son verdiğim çözüm o kadar basit olmayabilir, ancak tamamen kurtarıcıdır ve büyük numaralandırmalarla bile kodunuzun performansına zarar vermez:

public enum Example {

    UNKNOWN(0, "unknown"), ENUM1(1, "enum1"), ENUM2(2, "enum2"), ENUM3(3, "enum3");

    private static HashMap<Integer, Example> enumById = new HashMap<>();
    static {
        Arrays.stream(values()).forEach(e -> enumById.put(e.getId(), e));
    }

    public static Example getById(int id) {
        return enumById.getOrDefault(id, UNKNOWN);
    }

    private int id;
    private String description;

    private Example(int id, String description) {
        this.id = id;
        this.description= description;
    }

    public String getDescription() {
        return description;
    }

    public int getId() {
        return id;
    }
}

Endeksinizle asla menzil dışına çıkmayacağınızdan eminseniz ve UNKNOWNyukarıda yaptığım gibi kullanmak istemiyorsanız , elbette şunları da yapabilirsiniz:

public static Example getById(int id) {
        return enumById.get(id);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.