私はJava enumが実際にどのように機能するかを理解しようとしていましたが、コンストラクタが宣言されている通常のJavaクラスに非常に似ているという結論に達しましたプライベート。
私はこの結論にたどり着きましたが、それはあまり考えに基づいたものではありませんが、何かを逃したかどうかを知りたいのです。
以下は、単純なJava enumと同等のJavaクラスの実装です。
public enum Direction {
ENUM_UP(0, -1),
ENUM_DOWN(0, 1),
ENUM_RIGHT(1, 0),
ENUM_LEFT(-1, 0);
private int x;
private int y;
private Direction(int x, int y){
this.x = x;
this.y = y;
}
public int getEnumX(){
return x;
}
public int getEnumY(){
return y;
}
}
上記のコードと以下のコードの意味の違いは何ですか?
public class Direction{
public static final Direction UP = new Direction(0, -1) ;
public static final Direction DOWN = new Direction(0, 1) ;
public static final Direction LEFT = new Direction(-1, 0) ;
public static final Direction RIGHT = new Direction(1, 0) ;
private int x ;
private int y ;
private Direction(int x, int y){
this.x = x ;
this.y = y ;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
違い:
Java.lang.Enum
_を拡張し、そのすべてを取得します 素晴らしい機能 :.toString
_メソッド.name
_および_.ordinal
_特殊目的メソッドEnumSet
およびEnumMap
クラスで使用可能public static final
_フィールドを書き込まずにインスタンスの作成を簡素化する特別な構文を使用しますswitch
ステートメントで使用できますpublic static (Enum)[] values();
public static (Enum) valueOf(Java.lang.String);
private static final (Enum)[] $VALUES;
(values()
はこのクローンを返します)これらのほとんどは適切に設計されたクラスでエミュレートできますが、Enum
は、この特に望ましいプロパティのセットを使用してクラスを簡単に作成できるようにします。
質問に答えるには、基本的に、2つのアプローチに違いはありません。ただし、enumコンストラクトは、values()
、valueOf()
などの追加のサポートメソッドを提供します。これらのメソッドは、private-with-private-constructorアプローチで独自に記述する必要があります。 。
しかし、ええ、私はJava enumはJavaの他のクラスとほとんど同じで、フィールド、動作などを持つことができます。しかし、私にとってenumとプレーンクラスを区別するのは列挙型は、インスタンス/メンバーが事前に決定されているクラス/タイプです。任意の数のインスタンスを作成できる通常のクラスとは異なり、列挙型は既知のインスタンスにのみ作成を制限します。コンストラクタですが、列挙型はこれをより直感的にするだけです。
このブログページ をご覧ください。Java enum
sがバイトコードにコンパイルされる方法を説明しています。 2番目のコードサンプルは、Direction
と呼ばれるVALUES
オブジェクトの配列です。この配列は、enumのすべての可能な値を保持するため、実行できません
_new Direction(2, 2)
_
(たとえばリフレクションを使用して)、それを有効なDirection
値として使用します。
さらに、@ Eng.Fouadが正しく説明しているように、values()
、valueOf()
、およびordinal()
はありません。
人々が指摘したように、あなたはvalues()
、valueOf()
、およびordinal()
を失います。 Map
とList
の組み合わせを使用すると、この動作をかなり簡単に複製できます。
public class Direction {
public static final Direction UP = build("UP", 0, -1);
public static final Direction DOWN = build("DOWN", 0, 1);
public static final Direction LEFT = build("LEFT", -1, 0);
public static final Direction RIGHT = build("RIGHT", 1, 0);
private static final Map<String, Direction> VALUES_MAP = new LinkedHashMap<>();
private static final List<Direction> VALUES_LIST = new ArrayList<>();
private final int x;
private final int y;
private final String name;
public Direction(int x, int y, String name) {
this.x = x;
this.y = y;
this.name = name;
}
private static Direction build(final String name, final int x, final int y) {
final Direction direction = new Direction(x, y, name);
VALUES_MAP.put(name, direction);
VALUES_LIST.add(direction);
return direction;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public static Direction[] values() {
return VALUES_LIST.toArray(new Direction[VALUES_LIST.size()]);
}
public static Direction valueOf(final String direction) {
if (direction == null) {
throw new NullPointerException();
}
final Direction dir = VALUES_MAP.get(direction);
if (dir == null) {
throw new IllegalArgumentException();
}
return dir;
}
public int ordinal() {
return VALUES_LIST.indexOf(this);
}
@Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + name.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Direction other = (Direction) obj;
return name.equals(other.name);
}
@Override
public String toString() {
return name;
}
}
ご覧のように;コードはすぐに非常に不格好になります。
このクラスでswitch
ステートメントを複製する方法があるかどうかはわかりません。あなたはそれを失います。
主な違いは、各enum
クラスが暗黙的に_Enum<E extends Enum<E>>
_クラスを拡張することです。これはそれにつながります:
enum
オブジェクトには、name()
やordinal()
などのメソッドがありますenum
オブジェクトには、特別なtoString()
、hashCode()
、equals()
、およびcompareTo()
の実装がありますenum
オブジェクトは、switch
演算子に適しています。上記のすべては、Direction
クラスのバージョンには適用されません。これが「意味」の違いです。