# Generics mit Enums



## hupfdule (14. Jun 2009)

Hi, folgendes Codeschnipsel

```
public class Test<E extends Enum>{
  public Test(){
    for (E enumValue : E.values()){
      ...
    }
  }
}
```

scheitert, weil die Methode values() nicht gefunden wird.

Wo liegt mein Fehler?
Was kann ich tun, um hier die Werte des Enums abzufragen?

Vielen Dank für die Hilfe.


----------



## Noctarius (14. Jun 2009)

Zur Laufzeit gibt es keine Generics mehr.


----------



## faetzminator (14. Jun 2009)

Du versuchst von der Klasse E eine statische Methode values() aufzurufen. Du brauchst eine Instanz, welche du bearbeiten kannst, z.B. so:

```
public class Test<E extends Enum>{
  public Test(E e){
    for (E enumValue : e.values()){
      [...]
    }
  }
}
```


----------



## Noctarius (14. Jun 2009)

Nein eben nicht von der Klasse E, sondern vom Generic-Value E, welches eine x-beliebige Klasse sein kann die sich von Enum ableitet (also im Normalenfall ein Enum ), trotzdem ist das Generic zur Laufzeit weg


----------



## hupfdule (14. Jun 2009)

Noctarius hat gesagt.:


> Zur Laufzeit gibt es keine Generics mehr.



Das ist ja richtig, aber inwiefern ist das hier das Problem? Das E wird durch einen konreten Enum-Typ ersetzt.
Dieser kann aber doch zur Laufzeit abgefragt werden. Die Generics sollten hier doch nicht das Problem sein, oder?


----------



## hupfdule (14. Jun 2009)

faetzminator hat gesagt.:


> Du versuchst von der Klasse E eine statische Methode values() aufzurufen.



Aber die Methode ist doch statisch. Würde ich einen konkreten Enum-Typen nehmen, würde ich die Methode auch statisch aufrufen.

BTW: In der API von java.lang.Enum ist die Methode values() nicht aufgelistet. Wo finde ich sie in der API?


----------



## Noctarius (14. Jun 2009)

Na das ist nicht so ganz einfach. Generics werden nicht an allen Stellen beim Kompilieren durch den konkreten Typen ersetzt. Z.B. wird aus:

```
class Foo<E> {
    private E foo;
}
```

nicht:

```
class Foo<Konkret> {
    private Konkret foo;
}
```

aber:

```
class Foo<Konkret> {
    private Object foo;
}
```


Anders ist es bei Signaturen von Methoden. Dort werden z.B. Rückgabewerte ersetzt. Ein Generic ist Typensicherheit zur Entwicklungszeit, damit ist es egal welche Klasse foo später hat, solange der Rückgabewert der Methoden (innerhalb von eigenen Klasse - z.B. Getter/Setter) stimmt um diese zu identifizieren.

Was du aber brauchst ist entweder die Klasse selber Class<E extends Enum> für Reflection oder die Instanz der Klasse (z.B. im Konstruktor übergeben).


edit: values wird vom Compiler beim kompilieren eines Enum automatisch angelegt. Es ist im Endeffekt nichts anderes als ein statischer Konstrukter, der ein Array mit allen Werten des Enum füllt. Daher ist sie im Javadoc auch nicht zu finden. Steht glaub ich nur im Text erwähnt. Ansonsten im JLS, im Bereich für Enums.


----------



## hupfdule (14. Jun 2009)

Noctarius hat gesagt.:


> Was du aber brauchst ist entweder die Klasse selber Class<E extends Enum> für Reflection oder die Instanz der Klasse (z.B. im Konstruktor übergeben).



Hmm,
was mach ich denn dann nun? Wie muss der Konstruktor aussehen? Ich hätte es ja so versucht:

```
public class Test<E extends Enum>{
  public <Class <E extends Enum>> Test(E e){
    for (E enumValue : e.values()){
      ...
    }
  }
}
```

Das lässt sich allerdings noch nicht mal kompilieren. Wie müsste der Konstruktor aussehen?
Und mein zweites Problem: Wie lege ich fest, dass im Konstruktor nur das Enum übergeben werden darf, das auch bei der Klassendeklaration angegeben wurde?


----------



## Noctarius (14. Jun 2009)

```
public class Test<E extends Enum> {
    public Test(E e) {
        for (E value : e.value()) {
            ...
        }
    }
}
```


----------



## hupfdule (14. Jun 2009)

Ah, jetzt hab ich es:


```
public class Test{
   public <E extends Enum> Test(Class<E> enumType){
      for (E enumValue : enumClass.values()){
      }
   }
}
```


----------



## hupfdule (14. Jun 2009)

Noctarius hat gesagt.:


> ```
> public class Test<E extends Enum> {
> public Test(E e) {
> for (E value : e.value()) {
> ...



Nein, das geht ja eben gerade nicht. Das ist ja das was faetzminator geschrieben hat.
Die von mir gepostete Version funktioniert jetzt. 
Allerdings übergebe ich den Wert dort halt nur per Konstruktor, ich kann die Klasse selbst nicht entsprechend typisieren, um für Methoden diese Typen als Rückgabewerte zu definieren. Also auch noch nicht die ideale Lösung.


----------



## Noctarius (14. Jun 2009)

Du hast da in deinem Beispiel doch garkeinen Konstruktor geschrieben Oo


----------



## hupfdule (14. Jun 2009)

Noctarius hat gesagt.:


> Du hast da in deinem Beispiel doch garkeinen Konstruktor geschrieben Oo



Ähm, hab ich nicht? Was dann?


----------



## Noctarius (14. Jun 2009)

Du hast eine Methode die zufällig Test heißt. Ein Konstruktor hat keinen Rückgabewert.


----------



## hupfdule (14. Jun 2009)

Das ist kein Rückgabewert, das ist die Angabe des Generic Types für den Konstruktor. Es ist und bleibt ein Konstruktor.

Aber lass uns bitte nicht ums Thema drum herum reden. Meine Anforderung habe ich immer noch nicht gelöst. Ich möchte für die Klasse den Generics-Typ angeben, der ein Enum sein muss. Ich muss im Konstruktor auf die möglichen Enum-Werte zugreifen können. Es soll sichergestellt sein, dass der im Konstruktor übergebene Enum der selbe Typ ist, wie bei der Klassendeklaration angegeben.


----------



## Noctarius (14. Jun 2009)

Jo stimmt hatte vorhin irgendwie was von Class<E extends Enum> ... gelesen. Vermutlich verlesen oder so, keine Ahnung.


```
public class EnumTest {
	public static enum Foo {
		First,
		Second,
		Third
	}

	public static class Bar<E extends Enum<E>> {
		public Bar(Class<E> e) {
			for (E value : e.getEnumConstants()) {
				System.out.println(value.name());
			}
		}
	}
	
	
	
	public static void main(String[] args) {
		new Bar(Foo.class);
	}
}
```

So geht es zumindestens


----------



## hupfdule (15. Jun 2009)

Noctarius hat gesagt.:


> So geht es zumindestens


Ahhh! Danke dir. Genau. Das ist es! 
Besten Dank für die Hilfe.


----------

