# enums ineinander schachteln



## Marco Plaß (7. Sep 2007)

Hallo Forum,

zwecks intelligentem Zugriff auf Konstanten über einen Ordinaltyp gefallen mir enums sehr gut. Aber: ich bekomme keine Verschachtelung zustande. Am Besten lässt sich das an einem Beispiel erläutern.


```
public enum InnerEnum
{
    UNDEFINED (-1, "Undefiniert"),
    STAGE_1   ( 1, "first inner stage"),
    STAGE_2   ( 2, "second inner stage");
    private final Integer id;
    private final String  longName;
    InnerEnum (Integer id, String longName)
    {
        this.id         = id;
        this.longName   = longName;
    }
    @Override
    public String toString()
    {
        return "Stage: " + this.longName;
    }
}

public enum OuterEnum
{
    UNDEFINED (-1, "Undefiniert", null),
    STAGE_1   ( 1, "first outer stage", InnerEnum),
    STAGE_2   ( 2, "second outer stage", null);
    private final Integer   id;
    private final String    longName;
    private final InnerEnum innerenum;
    OuterEnum (Integer id, String longName, InnerEnum innerenum)
    {
        this.id         = id;
        this.longName   = longName;
        this.innerenum  = innerenum;
    }
    @Override
    public String toString()
    {
        return "Stage: " + this.longName;
    }
}

public class MainClass
{
    public static void main(String[] args)
    {
        OuterEnum outstage = OuterEnum.STAGE_1;
        System.out.println(outstage.toString());

    }

}
```

Spannend wird die Sache beim Aufruf des Konstruktors aus den drei Aufzählungen in OuterEnum (Zeile 24). Es soll eine spezielle enum als Parameter in den Konstruktor übergeben werden. Das Problem dabei ist, dass InnerEnum leider nicht statisch ist sondern nur seine Aufzählungen. Der Versuch, es statisch über


```
STAGE_1   ( 1, "first outer stage", myinner),
...
    static
    {
        InnerEnum myinner;
    }
```

machen scheitert daran, dass myinner bei STAGE_1 noch nicht existiert (m.E.).

Nun stehe ich ziemlich ratlos da. Hat jemand schon mal dieses Problem gelöst? Bin für alle Ratschläge dankbar.

Marco


----------



## SlaterB (7. Sep 2007)

verstehe ich nicht,
was soll denn der Parameter InnerEnum bedeuten?
du musst eine konkrete InnerEnum übergeben, z.B. InnerEnum.UNDEFINED 

das klappt bei mir, was genau hast du für einen Fehler?


----------



## Marco Plaß (7. Sep 2007)

Genau das möchte ich eben nicht (ich will keine eine konkrete Auswahl aus der enum, ich will das ganze enum).

Mein Ziel ist es, hinter einem enum Eintrag eine ganze weitere adressieren zu können abhängig von der ersten. Für das Beispiel soll so etwas funktionieren wie der Aufruf einer statischen Methode, die ein konkretes innerenum zurückgibt je nach übergebener id, z.B.

```
OuterEnum.STAGE_1.innerenum.getObject(id)
```

Dabei sind innerenum verschiedene enums, die jeweils das gleiche Interface implementieren.

Der erweiterte Beispielquellcode sieht dann so aus:

```
public interface InnerEnumBase
{
    public InnerEnum getObject(Integer id);
}

public enum InnerEnum implements InnerEnumBase
{
    UNDEFINED (-1, "Undefiniert"),
    STAGE_1   ( 1, "first inner stage"),
    STAGE_2   ( 2, "second inner stage");
    private final Integer id;
    private final String  longName;
    InnerEnum (Integer id, String longName)
    {
        this.id         = id;
        this.longName   = longName;
    }
    @Override
    public String toString()
    {
        return "Stage: " + this.longName;
    }
    public InnerEnum getObject(Integer id)
    {
        for (InnerEnum fmsorg: InnerEnum.values())
        {
            if (fmsorg.id==id)
                return fmsorg;
        }
        return InnerEnum.UNDEFINED; 
    }
}

public enum InnerEnum2 implements InnerEnumBase
{
...
}

public enum OuterEnum
{
    UNDEFINED (-1, "Undefiniert", null),
    STAGE_1   ( 1, "first outer stage", InnerEnum),
    STAGE_2   ( 2, "second outer stage", InnerEnum2);
...
}
```

Was einen Teil meiner Anforderungen erfüllt ist wenn ich alle Values mit übergebe. Damit verliere ich aber die schöne Handhabbarkeit des codes:

```
public enum OuterEnum
{
    UNDEFINED (-1, "Undefiniert", null),
    STAGE_1   ( 1, "first outer stage", InnerEnum.values()),
    STAGE_2   ( 2, "second outer stage", null);
    private final Integer   id;
    private final String    longName;
    private final InnerEnum[] innerenum;
    OuterEnum (Integer id, String longName, InnerEnum[] innerenum)
    {
        this.id         = id;
        this.longName   = longName;
        this.innerenum  = innerenum;
    }
    @Override
    public String toString()
    {
        return "Stage: " + this.longName;
    }
    static
    {
        InnerEnum myinner;
    }
}
```

Das gefällt mir nicht.


----------



## bygones (7. Sep 2007)

denke mal so wird das nicht gehen wie du willst.... die OuterEnum werden ja konkret initialisiert


```
STAGE_1   ( 1, "first outer stage", InnerEnum)
```
, d.h. hier MUSS eine vorhandene Variable da sein... bei jedem Konstruktor aufruf muss dies sein - da unterscheiden sich die Enums nicht von anderen Klassen

du kannst ja auch nicht schreiben

```
Point xy = new Point(unbekanntesX, unbekanntesY);
```
die Variablen muessen zum zeitpunkt des erstellens bekannt sein .

unter der praemisse ich habe das problem verstanden


----------



## Marco Plaß (7. Sep 2007)

genau das ist ja mein Problem. InnerEnum ist nicht da. Kann ja auch nicht, ist ja als enum per Definition abstrakt. Aber: Was ja faktisch dahinter steckt ist eine Ansammlung von Konstanten, auf die schön zugegriffen werden kann. Ich möchte also nicht nur die Aufzählungsobjekte sondern die ganze Aufzählung konkret statt abstrakt.

Vielleicht ist der Titel umzuformulieren zu "konkrete enums"?

Ihr werdet mir recht geben, dass einerseits der Zugriff auf ein solches (polymorphes enum) Konstrukt elegant ist und andererseits alle Informationen, die java benötigt, zur Designtime vorliegen müssten. Oder stehe ich da völlig auf dem Schlauch?


----------



## SlaterB (7. Sep 2007)

dass ein Enum ein Interface implementiert ist kein Problem,
das hat nix mit 'ich will das ganze enum' zu tun,

was du mit 'ich will das ganze enum' meinst verstehe ich immer noch nicht,
auf jeden Fall dürfte das auch wiederum nichts mit der Verschtelung oder der OuterEnum zu haben,
-----

erstelle doch erstmal eine Programm OHNE OuterEnum, nur mit InnerEnum, 
vielleicht noch mit einem einem Interface und einer weiteren gleichen Enum und dann


```
public class MainClass 
{ 
    public static void main(String[] args) 
    { 
        InnerEnum test = eas um Teufel willst du hier haben?
        // .. was soll damit passieren
    } 
}
```


----------



## SlaterB (7. Sep 2007)

vielleicht ist das hier das richtige für dich:


```
public class Test2
{

    public static void main(String[] args)
        throws Exception
    {
        MyEnum[] enums = A.values();
        System.out.println("eine MyEnum: " + enums[0].toString());
        enums = B.values();
        System.out.println("eine MyEnum: " + enums[0].toString());
    }
}


interface MyEnum
{
}


enum A
    implements MyEnum
{
    Test, Test2
}


enum B
    implements MyEnum
{
    Test3
}
```



falls das Array nicht ausreicht kannst du dir noch eine Hilfsklasse definieren, 
aber direkt auf die Klassen und z.B. die valueOf()-Operation kannst du dynamisch wohl nicht zugreifen


----------



## Marco Plaß (7. Sep 2007)

Deine Lösung ist so ähnlich, wie die enum.values() im Konstruktor mit zu übergeben. Das funktioniert auch, hat aber die gleichen Nachteile. Hier nochmal das gewünschte konkrete Beispiel, welches natürlich in den Zeilen 63 und 64 nicht funktioniert aber trotzdem mein Ziel zeigt:

```
public interface IFStelle2Base
{
    public IFStelle2Base getObject(Integer id);
}
public enum KlassSysStelle11 implements IFStelle2Base
{
    UNDEFINED (-1, "Undefiniert"),
    NOTE      ( 1, "Notebooks"),
    MONI      ( 2, "Monitore");
    private final Integer id;
    private final String  longName;
    KlassSysStelle11 (Integer id, String longName)
    {
        this.id         = id;
        this.longName   = longName;
    }
    @Override
    public String toString()
    {
        return "Stage: " + this.longName;
    }
    public KlassSysStelle11 getObject(Integer id)
    {
        for (KlassSysStelle11 currenum: KlassSysStelle11.values())
        {
            if (currenum.id==id)
                return currenum;
        }
        return KlassSysStelle11.UNDEFINED; 
    }
}
public enum KlassSysStelle12 implements IFStelle2Base
{
    UNDEFINED (-1, "Undefiniert"),
    ROMA         ( 1, "Romane"),
    SACH         ( 2, "Sachbuecher");
    private final Integer id;
    private final String  longName;
    KlassSysStelle12 (Integer id, String longName)
    {
        this.id         = id;
        this.longName   = longName;
    }
    @Override
    public String toString()
    {
        return "Stage: " + this.longName;
    }
    public KlassSysStelle12 getObject(Integer id)
    {
        for (KlassSysStelle12 currenum: KlassSysStelle12.values())
        {
            if (currenum.id==id)
                return currenum;
        }
        return KlassSysStelle12.UNDEFINED; 
    }
}
public enum KlassSysStelle1
{
    UNDEFINED (-1, "Undefiniert", null),
    COMP   ( 1, "Computer",       KlassSysStelle11),
    BUEC   ( 2, "Buecher",        KlassSysStelle12);
    private   final Integer       id;
    private   final String        longName;
    protected final IFStelle2Base stelle2;
    KlassSysStelle1 (Integer id, String longName, IFStelle2Base stelle2)
    {
        this.id         = id;
        this.longName   = longName;
        this.stelle2    = stelle2;
    }
    @Override
    public String toString()
    {
        return "Oberkategorie: " + this.longName;
    }
    public static KlassSysStelle1 getObject(Integer id)
    {
        for (KlassSysStelle1 currenum: KlassSysStelle1.values())
        {
            if (currenum.id==id)
                return currenum;
        }
        return KlassSysStelle1.UNDEFINED; 
    }
}
import java.io.*;

public class MainClass
{
    public static void main(String[] args)
    {
        OuterEnum outstage = OuterEnum.STAGE_1;
        System.out.println(outstage.toString());
        
        System.out.println("Klassifizierungssystem Beispiel eBay");
        System.out.println("ebay+Computer(1)+Notebooks   (1)");
        System.out.println("    +-----------+Monitore    (2)");
        System.out.println("    +Buecher (2)+Romane      (1)");
        System.out.println("    +-----------+Sachbuecher (2)");
        System.out.println("Klassifizierungsschlüssel eingeben:");
        Integer stelle1 = -1;
        Integer stelle2 = -1;
        try
        {
            stelle1 = System.in.read();
            stelle2 = System.in.read();
        }
        catch (IOException e)
        {
            System.err.println(e.getLocalizedMessage());
        }
        KlassSysStelle1 mystage1 = KlassSysStelle1.getObject(stelle1);
        IFStelle2Base   mystage2 = mystage1.stelle2.getObject(stelle2);
        System.out.println("Sie befinden sich in der Navigation auf "+mystage1.toString()+"-"+mystage2.toString());
    }

}
```


----------



## SlaterB (7. Sep 2007)

tja, mit ein bisschen tricksen kann man das schon schaffen, wenn es nicht noch weiter geht,
z.B. könntest du UNDEFINED immer als erstes Element definieren,

dann kannst du
 return KlassSysStelle1.UNDEFINED;
durch
 return array[0];
ersetzen

der Vergleich der Id ist gar kein Problem, du kannst ja im Interface (und allen Enums) eine Operation getId() definieren,

oder du nimmst einfach die Postition im Array als Id,
es ist generell etwas ungewöhlich, einer nummerierten Enum auch noch eine Id zuzuweisen..

wenn du mit einem Interface arbeitest hast du im laufenden Programm natürlich nur normale Objekte, keine Enums,
also bietet sich die Operation getId() in jedem Fall an,
die könnte dann aber die 'natürliche' Id zurückgeben:

    public int getId() {
        return this.ordinal(); // == Position im Array
    }


----------



## Marco Plaß (7. Sep 2007)

Leider bin ich dann bei arrays statt bei enums. Da wollte ich halt gerade nicht hin. Wenn es nicht anders geht werde ich es so machen :cry:.


----------



## SlaterB (7. Sep 2007)

das Problem hast du übrigens bei beliebigen Klassen in Java und auch statischen Variablen oder sonstigem

du kannst nirgendwo Klasse.irgendwas; aufrufen, wobei Klasse dynamisch ist, 
ausgenommen natürlich Polymorphie/ Interfaces


----------

