11

「値」が同じ 2 つの定数を持つ列挙型を定義したいと考えています。これら 2 つの定数を重複と呼びます。次の例を考えてみましょう: ブラウザーの種類のリストを定義したいのですが、以下のように、リテラルの "IE" と "InternetExplorer" の両方が必要です。

enum Browser {
    CHROME("chrome"),
    FIREFOX("firefox"),
    IE("ie"),
    INTERNETEXPLORER("ie");

    String type;
    Browser(String type) {
        this.type = type;
    }
}

ただし、これでは、次のコードは失敗します。

Browser a = Browser.IE;
Browser b = Browser.INTERNETEXPLORER;
Assert.assertTrue(a==b);

考えられる唯一の回避策は、ブラウザー インスタンスの内部値を返す型のvalue()メソッドを追加することです。Browserそして、等価テストコードは次のようになります

Assert.assertTrue(a.value()==b.value())

これは良くありません。それで、誰かがより良い考えを持っていますか?

equals()JavaがEnum<T>クラスのようなメソッドをオーバーライドできないのはなぜですか?

編集

OK、回答とコメントをありがとう。私の当初の考えが列挙型の目的に反していたことに同意します。次の変更が私のニーズを満たすことができると思います。

public enum Browser {
   CHROME,
   FIREFOX,
   IE;

   public static Browser valueOfType(String type) {
       if (b == null) {
            throw new IllegalArgumentException("No browser of type " + type);
       switch (type.toLowerCase()) {   
          case "chrome":
               return Browser.CHROME;
          case "firefox":
               return Browser.FIREFOX;
          case "ie":
          case "internetexplorer":
          case "msie":
               return Browser.IE;
          default:
               throw new IllegalArgumentException("No browser of type " + type);
       }
   }
}
4

7 に答える 7

10

この場合、階層的な列挙のトリックがおそらく必要です。それは比較の問題を解決しませんが、それはあなたの問題に非常に良い代替手段を提供します。

http://java.dzone.com/articles/enum-tricks-hierarchical-data

上記のサイトのコードを少し簡略化して直接引用します。

public enum OsType {
    OS(null),
        Windows(OS),
            WindowsNT(Windows),
                WindowsNTWorkstation(WindowsNT),
                WindowsNTServer(WindowsNT),
            WindowsXp(Windows),
            WindowsVista(Windows),
            Windows7(Windows),
        Unix(OS),
            Linux(Unix),
    ;
    private OsType parent = null;

    private OsType(OsType parent) {
        this.parent = parent;
    }
}
于 2012-09-20T12:12:49.707 に答える
9

これを行う簡単な方法の 1 つは、列挙型クラス内にインスタンス変数を配置することです。

enum Browser {
    CHROME,
    FIREFOX,
    INTERNETEXPLORER;
    public static final Browser IE=INTERNETEXPLORER;
}

次に、IE は単に のエイリアスとして機能する必要INTERNETEXPLORERがあり、それらを交換可能に使用できます。

編集: IE の作成を提案してくれた big_m に感謝しますfinal!

EDIT2: このトリックはほとんどのコードで機能するはずですが、switch/case. 次に例を示します。

Browser b;
switch(b){
    case Browser.CHROME:
        //code for chrome
        break;
    case Browser.IE: // <---- SYNTAX ERROR, use Browser.INTERNETEXPLORER in this case
        //code for internet explorer
        break;
}
于 2016-05-07T18:48:14.797 に答える
8

各列挙型は、 としてEnum定義equals()されるクラスを相互に拡張しますfinal。これは、enum が通常のクラスではないために行われます。JVM は、各 enum 要素が一意であることを保証します。つまり、1 つの JVM 内に各要素のインスタンスが 1 つだけ存在します。

switchこれは、たとえば、ステートメントなどで列挙型を使用するために必要です。

あなたがやろうとしているのは、この概念に反することです:同じ列挙型の2つの等しいメンバーが必要です.

ただし、他の解決策を提供できますIE。メンバーを 1 つだけ定義します。String[]任意のエイリアスで適切なメンバーを見つけることができる列挙型とメソッドにメンバーを定義します。

public enum Browser {


    CHROME("Chrome"),
    FIREFOX("FireFox"),
    IE("IE", "MSIE", "Microsoft Internet Exporer"),
    ;

    private String[] aliases;

    private static Map<String, Browser> browsers = new HashMap<>();
    static {
        for (Browser b : Browser.values()) {
            for (String alias : b.aliases) {
                browsers.put(alias, b);
            }
        }
    }

    private Browser(String ... aliases) {
        this.aliases = aliases;
    }

    public static Browser valueOfByAlias(String alias) {
        Browser b = browsers.get(alias);
        if (b == null) {
            throw new IllegalArgumentException(
                    "No enum alias " + Browser.class.getCanonicalName() + "." + alias);
        }
        return b;
    }
}
于 2012-09-20T12:03:39.650 に答える
2

列挙型のメソッドをオーバーライドすることはできませんがequals()、たとえオーバーライドできたとしても、==オペレーターはメソッドを実行しません。例equals()にする方法はありません。a == btrue

私が考えることができる最も近いものは、ユーティリティ(静的)メソッドです:

enum Browser {
    CHROME("chrome"),
    FIREFOX("firefox"),
    IE("ie"),
    INTERNETEXPLORER("ie");

    private final String type;
    Browser(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public static boolean equals(Browser b1, Browser b2) {
        return b1.type.equals(b2.type);
    }
}

また、私が作ることに注意してくださいtype private final。そのまま、これを行うことができます:

IE.type = "netscape"; // would be allowed
于 2012-09-20T11:53:23.600 に答える
0

Enumクラスで書かれたように

ただし、このクラスを拡張しても、クラスが列挙型になるわけではありません。これは、コンパイラが特別な情報を生成する必要があるためです。

参照方法に基づいた等価性をサポートするためにequalsは、最終的な方法です。

関連する列挙型のEnumSet作成に使用でき、メソッドを使用できます。EnumSetcontains

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
    Browser.INTERNETEXPLORER);

したがって、コードは次のようになります。

public enum Browser {
CHROME("chrome"), FIREFOX("firefox"), IE("ie"), INTERNETEXPLORER("ie");

String type;

Browser(String type) {
    this.type = type;
}

public static EnumSet<Browser> MSE = EnumSet.of(Browser.IE,
        Browser.INTERNETEXPLORER);

public static void main(String[] args) {
    System.out.println(MSE.contains(Browser.IE));//true
    System.out.println(MSE.contains(Browser.INTERNETEXPLORER));//true
}
}
于 2012-09-20T12:24:19.803 に答える
0

実際にすべきことは、入力から列挙型への変換を正規化することです。つまり、(ユーザー/データ ストアからの) 入力が IE/INTERNETEXPLORER の場合、Browser.IE に解決する必要があります。これにより、列挙型が IE か INTERNETEXPLORER かを確認するためのコード内の多くの冗長なチェックが削除されます。

于 2012-09-20T11:53:43.170 に答える
-2

文字列値と重複するIEインスタンスを削除しますが、役に立たない...

enum Browser {
    CHROME,
    FIREFOX,
    IE

小文字の表現が必要な場合は、必要なときに列挙名から変換するだけです。

于 2012-09-20T11:47:35.240 に答える