Perché i seguenti campi enumerati estendono la loro classe base o enum base?

0

Riguardo enum in java come ho capito è

Esempio enum

public enum Strategy {

    STRATEGY_A {
        @Override
        void execute(){
            System.out.print("Executing strategy A");
        }
    },

    STRATEGY_B {
        @Override
        void execute(){
            System.out.print("Executing strategy B");
        }
    };

    abstract void execute();
}

Questo sarebbe compilato per qualcosa di simile

public abstract class Strategy extends java.lang.Enum<Strategy> {
  public static final Strategy STRATEGY_A;
  public static final Strategy STRATEGY_B;
  private static final Strategy[] $VALUES;
  public static Strategy[] values();
  public static Strategy valueOf(java.lang.String);
  private Strategy();
  abstract void execute();
  Strategy(java.lang.String, int, Strategy$1);
  static {};
}

e l'enum STRATEGY_A sarebbe come una sottoclasse che estende la sua classe base STRATEGY

final class Strategy$1 extends Strategy {
  Strategy$1(java.lang.String, int);
  void execute();
}

Potrei ottenere quanto sopra con l'aiuto di javap leggendo il file della classe.

Per quanto ho capito, i campi enum (o) le costanti non sono altro che oggetti di classe di enum. Ad esempio

public enum Fruits {
APPLE;    //APPLE would be the instance of Fruits
ORANGE;   //ORANGE would be the instance of Fruits
GRAPES;   //GRAPES would be the instance of Fruits
}

Ma perché enum ha archiviato STRATEGY_A e STRATEGY_B estendere la classe base o l'enum di base STRATEGY ? Non ho potuto distinguere tra "enum fields (APPLE, ORANGE)" e "enum sottoclassi (STRATEGY_A, STRATEGY_B)" come sopra. Cosa significano veramente l'uno dell'altro?

Modifica

Tutti questi dubbi sono venuti mentre si implementa il modello di strategia con enum .

STRATEGY PATTERN .

    
posta rm -rf star 09.03.2017 - 08:44
fonte

3 risposte

4

Come avresti scritto la classe enum come se la struttura enum non fosse stata aggiunta in Java? Lo implementeresti in questo modo:

public abstract class Strategy {
    public final static Strategy
        STRATEGY_A = new Strategy(){
            @Override
            void execute(){
                System.out.print("Executing strategy A");
            }
        },
        STRATEGY_B = new Strategy(){
            @Override
            void execute(){
                System.out.print("Executing strategy B");
            }
        };

    abstract void execute();
}

Quando compilerai questo corso, genererà anche nuove classi (il seguito è di javap ):

public abstract class Strategy {
  public static final Strategy STRATEGY_A;
  public static final Strategy STRATEGY_B;
  public Strategy();
  abstract void execute();
  static {};
}
final class Strategy$1 extends Strategy {
  Strategy$1();
  void execute();
}
final class Strategy$2 extends Strategy {
  Strategy$2();
  void execute();
}

Essenzialmente questo è lo stesso di quello che hai ottenuto per l'enum:

public abstract class Strategy extends java.lang.Enum<Strategy> {
  public static final Strategy STRATEGY_A;
  public static final Strategy STRATEGY_B;
  public static Strategy[] values();
  public static Strategy valueOf(java.lang.String);
  abstract void execute();
  Strategy(java.lang.String, int, Strategy$1);
  static {};
}
final class Strategy$1 extends Strategy {
  Strategy$1(java.lang.String, int);
  void execute();
}
final class Strategy$2 extends Strategy {
  Strategy$2(java.lang.String, int);
  void execute();
}

Avrebbe un aspetto migliore se li visualizzi come classi anonime?

Ora, perché le classi non sovrascritte non hanno implementazioni? Questo perché non sono necessarie classi anonime.

Allo stesso modo, per le enumerazioni che hanno solo alcuni campi che annullano il valore, solo quei campi avranno sottoclassi. Vedi questo file Foo.java:

public enum Foo{
    FOO_A,
    FOO_B,
    FOO_C{
        @Override public void bar(){ System.out.println(2); }
    },
    FOO_D{
        @Override public void bar(){ System.out.println(2); }
    },
    FOO_E{
        @Override public void bar(){ System.out.println(3); }
    };
    public void bar(){ System.out.println(1); }
}

È compilato in:

final class Foo$1 extends Foo {
  Foo$1(java.lang.String, int);
  public void bar();
}
final class Foo$2 extends Foo {
  Foo$2(java.lang.String, int);
  public void bar();
}
final class Foo$3 extends Foo {
  Foo$3(java.lang.String, int);
  public void bar();
}
public class Foo extends java.lang.Enum<Foo> {
  public static final Foo FOO_A;
  public static final Foo FOO_B;
  public static final Foo FOO_C;
  public static final Foo FOO_D;
  public static final Foo FOO_E;
  public static Foo[] values();
  public static Foo valueOf(java.lang.String);
  public void bar();
  Foo(java.lang.String, int, Foo$1);
  static {};
}

Questo è simile all'output di questa classe:

public class Foo{
    public final static Foo FOO_A = new Foo(),
    FOO_B = new Foo(),
    FOO_C = new Foo(){
        @Override public void bar(){ System.out.println(2); }
    },
    FOO_D = new Foo(){
        @Override public void bar(){ System.out.println(2); }
    },
    FOO_E = new Foo(){
        @Override public void bar(){ System.out.println(3); }
    };
    public void bar(){ System.out.println(1); }
}

Quindi, alla fine, la tua domanda non regge, non c'è bisogno di differenziare le sottoclassi o meno, perché si comportano come classi anonime. Se capisci abbastanza bene la sottoclasse, capiresti che non c'è alcuna differenza tra la sottoclasse o meno se la usi correttamente (che include non usare i riflessi).

    
risposta data 09.03.2017 - 10:07
fonte
3

I singoli campi in questo caso possono essere solo istanze di sottoclassi perché hanno implementazioni differenti del metodo execute() . Se avessero solo campi con valori diversi, potrebbero essere tutti istanze della stessa classe, ma se hanno un comportamento diverso, ciò è possibile solo con sottoclassi.

    
risposta data 09.03.2017 - 09:12
fonte
0

Con l'aiuto della risposta di @ PEMapModder posso chiarire quanto segue

    public enum Strategy {

    STRATEGY_A {
        @Override
        void execute(){
            System.out.print("Executing strategy A");
        }
    },

    STRATEGY_B {
        @Override
        void execute(){
            System.out.print("Executing strategy B");
        }
    };

    abstract void execute();
}

Questo è uguale a

    public abstract class Strategy {
    public final static Strategy
        STRATEGY_A = new Strategy(){
            @Override
            void execute(){
                System.out.print("Executing strategy A");
            }
        },
        STRATEGY_B = new Strategy(){
            @Override
            void execute(){
                System.out.print("Executing strategy B");
            }
        };

    abstract void execute();
}

Quindi è come Inner Inner Classes che è utile quando si crea un'istanza di un oggetto con determinate proprietà aggiuntive per classe come sovraccaricare o sovrascrivere i suoi metodi, senza dover effettivamente sottoclasse una classe.

Un esempio migliore per la classe interna anonima e perché è più utile è spiegato bene qui .

    
risposta data 09.03.2017 - 12:20
fonte

Leggi altre domande sui tag