15

なぜ Java 言語で aclassが an を拡張できないのか疑問に思っていenumます。

私は an のenum拡張について話しているのenumではありません (Java には多重継承がなく、それはenum暗黙的に extendsであるため、実行できません)、追加の列挙値ではなく、追加のメソッドのみを追加するためのjava.lang.Enumクラスです。 .extendsenum

何かのようなもの:

enum MyEnum
{
    ASD(5),
    QWE(3),
    ZXC(7);
    private int number;
    private asd(int number)
    {
        this.number=number;
    }
    public int myMethod()
    {
        return this.number;
    }
}

class MyClass extends MyEnum
{
    public int anotherMethod()
    {
        return this.myMethod()+1;
    }
}

このように使用するには:

System.out.println(MyClass.ASD.anotherMethod());

それで、誰かがこの制限の根拠を提供できますか (または、適切な JLS セクションを教えてくれますか)?

4

6 に答える 6

12

を拡張することはできませんenum。それらは暗黙的にfinal. JLS § 8.9から:

final列挙型は、クラス本体を持つ列挙型定数が少なくとも 1 つ含まれていない限り、暗黙的に存在します。

また、JLS §8.1.4 - スーパークラスとサブクラスから:

ClassTypeクラスEnumまたはその呼び出しに名前が付けられている場合は、コンパイル時エラーです。

基本的に、enumは事前定義された定数の列挙セットです。このため、この言語では で列挙型を使用できますswitch-cases。それらを拡張できるようにすることで、たとえば、スイッチケースの適格なタイプにはなりません。それとは別に、列挙型を拡張するクラスまたは他の列挙型のインスタンスは、拡張する列挙型のインスタンスにもなります。enumそれは基本的に s の目的を破ります。

于 2013-10-17T17:29:35.060 に答える
8

Java 1.5より前の古代では、おそらく次のような列挙を行うでしょう。

public class MyEnum {

public static final MyEnum ASD = new MyEnum(5);
public static final MyEnum QWE = new MyEnum(3);
public static final MyEnum ZXC = new MyEnum(7);

private int number;

private MyEnum(int number) {
    this.number = number;
}

public int myMethod() {
    return this.number;
    }

} 

この図には 2 つの重要な点があります。

  • 外部からのクラスのインスタンス化を許可しないプライベート コンストラクター
  • 実際の「列挙」値は静的フィールドに格納されます

拡張するときに最終的ではない場合でも、コンパイラには明示的なコンストラクターが必要であり、逆にスーパーコンストラクターを呼び出す必要があることに気付くでしょう。これはプライベートであるため不可能です。もう1つの問題は、スーパークラスの静的フィールドが、拡張したものではなく、そのスーパークラスのオブジェクトをまだ格納していることです。これで説明がつくと思います。

于 2013-10-17T18:02:02.430 に答える
3

なぜ彼らがこのようにしたのかについての答えは、次の質問から得られると思います。

あなたの例では、どのように MyClass をインスタンス化しますか? 列挙型は、ユーザーによって明示的に ( を介してnew MyEnum()) インスタンス化されることはありません。あなたは何かをしなければならないでしょうが、MyClass.ASDそれがどのように機能するかはわかりません。

基本的に、提案された追加でどの構文が機能するかわかりません。それがおそらく彼らがそれらを最終的なものにした理由などです...

編集が追加されました

元の Enum の作成者が事前に計画を立てていて (可能性は低い)、スレッド セーフについてあまり心配していない場合は、次のようにすることができます: (ところで、実際に製品コードでこれを行った人、YMMV に対して私はおそらく悲鳴を上げるでしょう。 )

public enum ExtendibleEnum {

   FOO, BAR, ZXC;

   private Runnable anotherMethodRunme;  // exact Interface will vary, I picked an easy one
                           // this is what gets "injected" by your other class

   public void setAnotherMethodRunMe(Runnable r) {  // inject here
      anotherMethodRunme= r;
   }

   public void anotherMethod() {  // and this behavior gets changed
      anotherMethodRunme.run();
   }
}
于 2013-10-17T17:35:47.573 に答える