Java で列挙型を拡張する

Sheeraz Gul 2023年10月12日
Java で列挙型を拡張する

このチュートリアルでは、Java で enum 機能を拡張する方法を示します。

Java で enum を拡張する

enum は一種のコンパイラ マジックと見なすことができます。これは、byte コードでは、enum がいくつかの static メンバーを持つクラスとして表され、抽象 java.lang.Enum から継承されているためです。

これが、enum が他のクラスまたは enum を拡張できない理由です。 Java では enum を拡張できないため、どのクラスでも enum を拡張することはできません。 次のコード例を使用して学習し、何が起こるか見てみましょう。

コード例:

package delftstack;

enum Cars { Audi, BMW, Marcedes }

public class Example extends Cars {
  public static void main(String... args) {}
}

上記のコードには Cars という名前の enum があり、クラス Example はそれを拡張しようとしています。 出力を参照してください:

/Example.java:5: error: cannot inherit from final Cars
public class Example extends Cars {
                             ^
/Example.java:5: error: enum types are not extensible
public class Example extends Cars {
       ^
2 errors

ご覧のとおり、クラスは enum を拡張できません。 enum を拡張することが不可能な場合でも、その機能を拡張することはできますか?

機能は、enum で実装されたメソッドとして定義できます。 たとえば、上記のコードの enum Cars は、各メンバーの抽象メソッドを宣言できます。 例を参照してください。

enum Cars {
  Audi {
    @Override
    public void drive() {}
  },
  BMW {
    @Override
    public void drive() {}
  },
  Mercedes {
    @Override
    public void drive() {}
  },
  ;
  public abstract void drive();
}

ご覧のとおり、各メンバーは drive() メソッドをオーバーライドできます。 しかし残念なことに、常に enum でメソッドを作成できるとは限りません:

  • enum がサードパーティ ライブラリまたは別のチームに属している場合、抽象メソッドの実装は許可されません。
  • drive() メソッドに必要な依存関係を持たないモジュールに属している場合。
  • enum が他の関数やデータでオーバーロードされている場合、読み取り不能になります。

これらの問題を解決し、Java の enum の機能を拡張できるソリューションがいくつか提供されています。

解決策 1: Java で enum をミラーリングする

名前が示すように、同じデータを持つ別の enum を作成する必要があります。 その新しい enumdrive() メソッドも実装するため、現在 2つの列挙型があります。

enum Cars のコード例:

enum Cars {
  Audi {
    @Override
    public void drive() {}
  },
  BMW {
    @Override
    public void drive() {}
  },
  Mercedes {
    @Override
    public void drive() {}
  },
  ;
  public abstract void drive();
}

enum DriveCars のコード例:

enum DriveCars {
  Audi {
    @Override
    public void drive() {}
  },
  BMW {
    @Override
    public void drive() {}
  },
  Mercedes {
    @Override
    public void drive() {}
  },
  ;
  public abstract void drive();
}

2 番目の enum は最初のもののミラーです。 機能を拡張することで、これらの列挙型の両方を使用できるようになりました。 name()valueof() である組み込みの enum メソッドを使用する必要があります。

使用方法については、次の例を参照してください。

Cars cars = ... DriveCars.valueOf(cars.name()).drive();

上記のコードは、enum DriveCarsenum Cars 機能がどのように使用されるかを示しています。 つまり、機能が拡張されます。

上記のコードの name() メソッドは final であり、オーバーライドすることはできず、valueOf メソッドはコンパイラによって生成されます。 これらの方法は両方とも、拡張操作に機能上のエラーがない場合、互いにうまく適合します。

enum Cars が変更された場合、上記のコードには 1つの問題があり、enum DriveCars は何も認識せず、namevalueof トリックの失敗を引き起こします。 この問題を解決するには、親ミラーがCarsであることをDriveCarsに知らせる必要があります。

そのために、static イニシャライザを使用して DriveCarsCars を比較できます。これは、両方の列挙型が一致しない場合に例外をスローします。 enumus ライブラリの例を次に示します。

enum DriveCars {
  ....static { Mirror.of(Cars.class); }
}

ユーティリティ クラスは、両方の列挙型が一致するかどうかをチェックします。 このメソッドは、name() および valueOf() トリックを検証します。

解決策 2: Java で enum をマップする

メソッドを 1つだけ保持する別の enum を作成したくない場合。 この場合、enum の代わりに interface を使用できます。 以下の例を参照してください。

public interface Driver {
  void drive();
}

この interface Driveenum Cars で使用するために、それらの間のマッピングを作成できます。 マップの例を次に示します。

Map<Cars, Driver> drivers = new EnumMap<>(Cars.class) {
  {
    put(Audi, new Driver() {
      @Override
      public void driver() {}
    }) put(BMW, new Driver() {
      @Override
      public void driver() {}
    }) put(Mercedes, new Driver() {
      @Override
      public void driver() {}
    })
  }
}

それらを使用するには、次の簡単なコードを使用します。

drivers.get(Cars).drive();

上記のコードで使用されている EnumMap は、各 enum メンバーが 1 回だけ表示されることを保証しますが、各メンバーのエントリは保証しません。

マップのサイズが列挙型のメンバーの数と等しいことを確認できます。

drivers.size() == Cars.values().length

enumus ライブラリは、この場合のユーティリティも提供します。マップが Cars に適合しない場合、IllegalStateException がスローされます。 ユーティリティは次のとおりです。

EnumMapValidator.validateValues(Cars.class, map, "Cars map");

上記の両方の方法は、機能を拡張して列挙型を強力にする方法を示しています。 enum を直接拡張することは不可能ですが、これらのトリックを使用して機能を拡張できます。

著者: Sheeraz Gul
Sheeraz Gul avatar Sheeraz Gul avatar

Sheeraz is a Doctorate fellow in Computer Science at Northwestern Polytechnical University, Xian, China. He has 7 years of Software Development experience in AI, Web, Database, and Desktop technologies. He writes tutorials in Java, PHP, Python, GoLang, R, etc., to help beginners learn the field of Computer Science.

LinkedIn Facebook

関連記事 - Java Enum