# Array von generischem Typ erstellen



## firefexx (22. Apr 2012)

Hallo, ich habe eine Art Liste geschrieben die Arrays von generischen Typen aufnehmen kann.

Wenn ich jetzt ein solches Array erstellen will schreibe ich:


```
T[] newArray = new T[N];
```
wobei N eine Variable für die Größe des Arrays ist.

Das resultiert im Fehler
"Generische Feldgruppe T kann nicht erstellt werden"

Dann versuche ich es so:

```
T[] newArray = new Object[N];
```

Dann gibts den Fehler
"Typabweichung: Konvertierung ob Object[] auf T[] nicht möglich"

Nächster Versuch:

```
T[] newArray = (T[]) new Object[N];
```

Endlich kein Fehler mehr, aber noch eine Warnung:
"Typsicherheit: Ungeprüfte Umwandlung von Object[] zu T[]"

Was will mir die Warnung sagen und kann ich das Problem irgendwie beheben?
(Abgesehen davon mit @SuppressWarnings zu arbeiten)

VG


----------



## Firephoenix (22. Apr 2012)

Hi,
du könntest dir dazu mal anschauen wie das ganze in ArrayList gelöst wurde:
java.util: ArrayList.java

Ich glaube eine 100% cleane Methode ohne Supress-Warnings oder Casting geht in dem Fall nicht, evtl hat hier jemand noch einen besseren Ansatz als die Java-Source 

Gruß


----------



## firefexx (22. Apr 2012)

Joa da halten sie das ganze als Object[], casten zwischendurch und benutzen SuppressWarnings.

Da kann ich wahrscheinlich direkt so machen wie ich zuletzt geschrieben habe?!

VG


----------



## xehpuk (22. Apr 2012)

Ohne @SuppressWarnings wird es nicht gehen.

Hier kommt dann aber ein richtig typsicheres Array raus:

```
@SuppressWarnings("unchecked")
static <T> T[] array(Class<T> componentType, int length) {
	return (T[]) Array.newInstance(componentType, length);
}
```


----------



## firefexx (22. Apr 2012)

Hi, danke für die Antwort.

Ich habe dazu noch ein paar Fragen.

Inwiefern bietet diese Methode eine Verbesserung gegenüber 
	
	
	
	





```
T[] newArray = (T[]) new Object[N];
```
  ? Was ist da der Vorteil?

Wie würde man die Methode dann aufrufen?

```
array(T.getClass(), N);
```
 ??
Ich würde wahrscheinlich schreiben 
	
	
	
	





```
T[] newArray = (T[]) Array.newInstance(T.getClass(), N);
```
 Müsste das gleiche sein, oder?


Und noch eine Frage zur Notation:

static <T> T[] array( ...
Wozu ist das <T> gut? Reicht es nicht wenn T[] da steht?
Wenn ich jetzt z.B. eine get Methode schreibe hat die folgende Signatur:

```
public T get(int pos)
```
Sollte da auch noch <T> vor das T??


VG


----------



## Spacerat (22. Apr 2012)

[OT]Tja, die Klasse Array... immer wenn man die verwendet, wird einem vorgeworfen Reflection zu verwenden, was ja vermieden werden soll. Ist vllt. noch jemand ausser mir der Ansicht, dass man die Methoden dieser Klasse getrost in die Klasse [c]java.util.Arrays[/c] zu kopieren, damit man blos nicht mehr in diesen Verdacht gerät? Ich finde nämlich, herauszufinden, ob es sich bei einem Objekt um ein Array handelt oder auch wie hier ein typsicheres generisches Array zu erstellen, hat nur noch sehr wenig mit Reflection zu tun. Ausserdem liesse sich dort eine Factory-Methode ebenso wie in xehpuks Beispiel einfügen und man hätte das SupressWarnings("unchecked") nicht mehr im eigenen Code.[/OT]
Also ich erstelle mir schon lange keine generischen Arrays mehr. Mit [c]List<UndTuecke>[/c] und den entsprechenden [c]toArray()[/c] Methoden geht das viel komfortabler.


----------



## Firephoenix (22. Apr 2012)

Noch als Literaturanmerkung zu dem Thread:

Das Buch "Effective Java" von Joshua Bloch behandelt unter anderem auch solche Fallstricke von Generics und liefert verschiedene Lösungsansätze bzw wägt verschiedene Lösungsmöglichkeiten gegeneinaner ab.

Ich hab leider das Werk gerade nicht zur Hand - fand aber die entsprechenden Kapitel zu Generics sehr lesenswert.

Gruß


----------



## firefexx (22. Apr 2012)

Hi, wieso ist es eigentlich so verpönt Reflection zu benutzen?
Ich sehe auch nicht wie dieser Anwendungsfall viel damit zu tun hat.


Zu deinem Vorschlag mit List und toArray Methoden:
Bei mir geht es grade sehr um Effizienz. Daher wird eine ArrayList implementiert (nicht die java.util) die eine Liste von Arrays erhält um die Vorteile von Arrays und Listen zu vereinen. Das Array jetzt als Liste zu verwalten wäre fatal für die Aufgabe. Da bleiben dann nur die Nachteile von verketteten Listen.
(bevor jetzt andere Vorschläge kommen: das ganze ist ne Uni-Aufgabe, ich darf mir jetzt nix komplett neues ausdenken).


----------



## Marco13 (22. Apr 2012)

firefexx hat gesagt.:


> Inwiefern bietet diese Methode eine Verbesserung gegenüber
> 
> 
> 
> ...



Der erste und wichtigste Vorteil ist: Sie funktioniert. Also, OHNE eine ClassCastException zu werfen ...  



> Wie würde man die Methode dann aufrufen?
> 
> ```
> array(T.getClass(), N);
> ...



Das geht beides nicht. Es gibt "T" nicht mehr, wenn das Programm läuft. T.getClass() kann man also nicht aufrufen. Das class-Objekt muss woanders herkommen. 



> Und noch eine Frage zur Notation:
> 
> static <T> T[] array( ...
> Wozu ist das <T> gut? Reicht es nicht wenn T[] da steht?
> ...



Das eine ist ein statischer Aufruf, das andere nicht. Genaugenommen kann man in spitzen Klammern den Typparameter vor eine Methode schreiben, wenn "T" sonst nirgendwo steht:

```
class Example // <- Hier steht kein Typ
{
    <T> void doit(T t0, T t1) { ... } // <- Aber hier: Der gilt nur für die Methode
}
```

Ggf. aufpassen:

```
class Example<T> // <- Hier steht ein Typ
{
    <T> void doit(T t0, T t1) { ... } // <- Aber hier AUCH - der "überdeckt" das "T" von oben
}
```
(das sollte aber z.B. Eclipse mit einer Warning ankreiden)


----------



## Marco13 (22. Apr 2012)

Ach ja, wenn du es genau wissen willst: DIE ultimative Referenz für alles, was mit Generics zu tun hat, ist die FAQ auf AngelikaLanger.com - Angelika Langer's Home Page - Angelika Langer Training/Consulting . Siehe z.B. auch AngelikaLanger.com - Arrays in Java Generics - Angelika Langer Training/Consulting


----------



## firefexx (22. Apr 2012)

Marco13 hat gesagt.:


> Der erste und wichtigste Vorteil ist: Sie funktioniert. Also, OHNE eine ClassCastException zu werfen ...


Also ich hab das eben mal getestet und da habe ich keine Exception bekommen oO




Marco13 hat gesagt.:


> Das geht beides nicht. Es gibt "T" nicht mehr, wenn das Programm läuft. T.getClass() kann man also nicht aufrufen. Das class-Objekt muss woanders herkommen.


Und woher?


----------



## Landei (22. Apr 2012)

Du musst es höchstpersönlich erzeugen und übergeben. Wird auch in den Java-APIs bei ähnlichen Problemen mit Type Erasure so gemacht (etwa im [c]EnumMap[/c]-Konstruktor).


----------



## Marco13 (22. Apr 2012)

firefexx hat gesagt.:


> Also ich hab das eben mal getestet und da habe ich keine Exception bekommen oO



KSKB or it didn't happen


----------



## firefexx (23. Apr 2012)

Ja xD also ich hab den Konstruktor erfolgreich mit T = Character aufrufen können und alle geschrieben Methoden erfolgreich getestet. Kann mir jemand ein Beispiel und einen Grund nennen dass es nicht funktioniert?

VG


----------



## Marco13 (23. Apr 2012)

Wenn das hier 

```
public class GenericArrayTest<T>
{
    T[] newArray = (T[]) new Object[3];
    
    public static void main(String[] args)
    {
        GenericArrayTest<String> s = new GenericArrayTest<String>();
        s.newArray[0] = "Hello";
    }
}
```

keine Exception wirft, hast du ein anderes Java als ich...


----------



## firefexx (23. Apr 2012)

Bei mir ist die Struktur etwas anders.

Eine Klasse ArrayList hält eine Liste von Listen-Elementen die wiederum Elemente beinhalten die einerseits ein solches generisches Array halten und sich merken wie viele Elemente in diesem Array sind (ungleich null). Um ein neues Element einzufügen gibt es eine add Methode in ArrayList. Diese erstellt auch ggf. das neue Array.


```
public static void main(String[] args) {
		ArrayList<String> l = new ArrayList<String>(3);
		l.add("Hello").add("2").add("3").add("4").add("5").add("6");
		System.out.println(l.get(0));
	}
```


relevanter Ausschnitt aus der add Methode:

```
@SuppressWarnings("unchecked")
			T[] newArray = (T[]) new Object[N];
		newArray[0] = element;
		KeyItem<T> newKeyItem = new KeyItem<T>(newArray, 1);
		list.add(newKeyItem);
```

Das klappt ohne Exception. ^^

VG


----------

