Najlepszy sposób na tworzenie wyliczenia ciągów?

364

Jaki jest najlepszy sposób, aby enumtyp reprezentował zestaw ciągów?

Próbowałem tego:

enum Strings{
   STRING_ONE("ONE"), STRING_TWO("TWO")
}

Jak mogę ich następnie użyć jako Strings?

Dori
źródło

Odpowiedzi:

605

Nie wiem, co chcesz zrobić, ale tak właśnie przetłumaczyłem twój przykładowy kod ...

package test;

/**
 * @author The Elite Gentleman
 *
 */
public enum Strings {
    STRING_ONE("ONE"),
    STRING_TWO("TWO")
    ;

    private final String text;

    /**
     * @param text
     */
    Strings(final String text) {
        this.text = text;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return text;
    }
}

Alternatywnie możesz utworzyć metodę gettera dla text.

Możesz teraz zrobić Strings.STRING_ONE.toString();

Buhake Sindi
źródło
3
Nie wiem, czy jest to wymóg kompilatora, ale private String textpowinien być ostateczny.
Jonathan
7
@ Tomás Narros Tak, nadal możesz przypisać go do konstruktora, o ile nie podasz wartości, gdy ogłaszasz to jako ostateczne.
Jonathan
28
@ The Elite Gentleman Byłoby źle, gdyby wartość stałej wyliczania zmieniała się w czasie wykonywania, więc nawet jeśli nie jest wymagana, finalbyłaby najlepsza.
Jonathan
8
Nie zapominaj, że Enums nie może być konstruowane newtak jak konstruktor private. Zasadniczo tworzenie obiektów jest zabronione i finalw tym przypadku nie jest tak naprawdę konieczne.
Buhake Sindi
6
@BuhakeSindi: to prawda, ale przypadkowo można skłonić setText(String)się do wyliczenia enum, co może rozpętać piekło :) finalrodzaj dokumentów, które zamierzają być stałe ze wsparciem kompilatora. Gdybyś użył Stringstałych, nie zadeklarowałbyś tego public static String, prawda?
TWiStErRob
104

Niestandardowe wartości ciągu dla wyliczenia

from http://javahowto.blogspot.com/2006/10/custom-string-values-for-enum.html

Domyślną wartością ciągu dla wyliczenia Java jest jego wartość nominalna lub nazwa elementu. Można jednak dostosować wartość ciągu, zastępując metodę toString (). Na przykład,

public enum MyType {
  ONE {
      public String toString() {
          return "this is one";
      }
  },

  TWO {
      public String toString() {
          return "this is two";
      }
  }
}

Uruchomienie następującego kodu testowego spowoduje:

public class EnumTest {
  public static void main(String[] args) {
      System.out.println(MyType.ONE);
      System.out.println(MyType.TWO);
  }
}


this is one
this is two
Vaichidrewar
źródło
16
To nie jest skuteczny sposób na zrobienie tego. Tworzy to nową klasę niestandardową dla każdej wartości w wyliczeniu. W powyższym przykładzie zobaczysz w binkatalogu: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class, który doda się naprawdę szybko. Najlepiej zrobić to jako oczekiwaną odpowiedź, przekazując wartości do konstruktora wyliczania. Właściwie nie zgadzam się z zastąpieniem toString(); Uważam, że lepiej jest użyć jawnego modułu pobierającego, na przykład getKey()ponieważ zastąpienie toString()może być nieoczekiwane przez innego użytkownika wyliczenia.
Matt Quigley,
całkowicie zgadzam się z @MattQuigley. W ten sposób zachęć użytkowników do korzystania z funkcji toString do celów, których nie należy używać. Jeśli potrzebujesz etykiety, wolisz dodać atrybut etykiety
Sebastien Lorber
Ponadto nie ma innej drogi (od łańcucha do obiektu wyliczanego), co prawdopodobnie będzie kiedyś wymagane.
Adrian Smith
przesłonięcie toString nie wpływa na wartośćOf (), prawda?
Dmitriusan
69

Użyj swojej name()metody:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.ONE.name());
    }
}

enum Strings {
    ONE, TWO, THREE
}

daje ONE.

Bart Kiers
źródło
17
Tak, ale Strings.STRING_ONE.name()daje „STRING_ONE”, a nie „JEDEN”. To po prostu nie jest dobra odpowiedź. Nie możesz mieć żadnego łańcucha, który nie byłby prawidłowym identyfikatorem Java itp.
Mark Peters,
2
@ Mark, prawda, nie może obsłużyć żadnej postaci. Jeśli PO chce tylko jednego znaku, to rozwiązanie jest prostsze niż sugestia Elitarnego Dżentelmena. Ale w rzeczy samej: jeśli zakres znaków przekracza te, które może mieć prawidłowy identyfikator Java, jest to niemożliwe. Słuszna uwaga.
Bart Kiers,
Jest bardzo rozsądne, aby mieć wewnętrzną konwencję nazewnictwa dla wyliczenia, która różni się od tego, co chcielibyśmy pokazać za pomocą toString () (szczególnie, jeśli użytkownik zobaczy dane wyjściowe), więc nie sądzę, że to właśnie OP było szukam.
Michael McGowan,
17
Na wynik z name()może mieć wpływ program zaciemniania. Jakiś czas temu napotkałem podobny problem. Na przykład w Proguard musisz obejść ten problem. Zobacz temat Przetwarzanie klas
wyliczeniowych
To jest doskonałe. Działa z wartościami takimi jak: var_name, var_superlong_but_not_toooooo_long_name, nawet etc (bez
18

Albo ustaw nazwę wyliczenia, aby była taka sama jak ciąg, który chcesz, lub, bardziej ogólnie, możesz powiązać dowolne atrybuty z wartościami wyliczenia:

enum Strings {
   STRING_ONE("ONE"), STRING_TWO("TWO");
   private final String stringValue;
   Strings(final String s) { stringValue = s; }
   public String toString() { return stringValue; }
   // further methods, attributes, etc.
}

Ważne jest, aby stałe były na górze, a metody / atrybuty na dole.

Adrian Smith
źródło
A także mieć prywatnego konstruktora.
Buhake Sindi,
1
Konstruktory enum są domyślnie prywatne i nie wymagają modyfikatora dostępu. Ale to dobra uwaga na temat modyfikatorów dostępu w ogóle, zaktualizowałem swój kod, aby dodać go do atrybutu i akcesorium.
Adrian Smith,
15

W zależności od tego, co rozumiesz przez „używaj ich jako ciągów”, możesz nie chcieć używać tutaj wyliczenia. W większości przypadków rozwiązanie zaproponowane przez Elitarnego Dżentelmena pozwoli ci użyć ich za pomocą metod toString, np. W System.out.println(STRING_ONE)lub String s = "Hello "+STRING_TWO, ale kiedy naprawdę potrzebujesz Ciągów (np. STRING_ONE.toLowerCase()), Możesz preferować zdefiniowanie ich jako stałych:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}
hd42
źródło
5
właściwie tego właśnie staram się unikać ...!
Dori
Właściwie, jeśli chcą także toLowerCase()mojego rozwiązania, mogą odejść Strings.STRING_TWO.toString().toLowerCase().
Buhake Sindi
Jasne, ale to nie używa ich jako ciągów znaków, jak to interpretowałem. Ponieważ Rrackham nie wydaje się wymagać takiego zastosowania, powinien oczywiście zastosować proponowane rozwiązanie enum.
hd42
6
Nie powinieneś używać interfacezamiast finalklasy z privatekonstruktorem. To zniechęcająca praktyka.
Aleks N.
1
@mils, rozwiązania wykorzystujące wyliczenia działają równie dobrze w przełączniku. Sugerowałbym to rozwiązanie tylko wtedy, gdy Strings są potrzebne bezpośrednio.
hd42
8

Możesz użyć tego dla łańcucha Enum

public enum EnumTest {
    NAME_ONE("Name 1"),
    NAME_TWO("Name 2");

    private final String name;

    /**
     * @param name
     */
    private EnumTest(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

I zadzwoń z głównej metody

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}
Shohel Rana
źródło
5

Jeśli nie chcesz używać konstruktorów i chcesz mieć specjalną nazwę dla metody, spróbuj tego:

public enum MyType {
  ONE {
      public String getDescription() {
          return "this is one";
      }
  },    
  TWO {
      public String getDescription() {
          return "this is two";
      }
  };

  public abstract String getDescription();
}

Podejrzewam, że jest to najszybsze rozwiązanie. Nie ma potrzeby używania zmiennych końcowych .

Adam111p
źródło
ale w tym przypadku nadal musisz wywołać metodę getDescription (), z której osoba pytająca chce wywołać JEDNĄ lub uzyskać do niej stały dostęp.
kinsley kajiva
Wolę to. Co się stanie, jeśli będzie musiał zaakceptować więcej informacji? Dzięki temu rozwiązaniu po prostu dodaj chronione metody abstrakcyjne i pomiń je. Ponadto nie trzeba zastępować metody toString (). Jest czysty i może być zaakceptowany jako najlepsza odpowiedź.
Arundev
0

Uzyskaj i ustaw wartości domyślne.

public enum Status {

    STATUS_A("Status A"),  STATUS_B("Status B"),

    private String status;

    Status(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}
Prawda
źródło