[ol]
[li]ArrayList s = new ArrayList(); [/li][/ol]
<- ich hab jetzt an sowas gedacht.
Sinn des generics ist es jedoch int,doube … Werte eingeben zukönnen.
Mein Problem ist jetzt wie mach is das mit dem Methoden-Kopf.
Oder zusammengefasst. Wie kann ich z.B. die unteren Werte einspielen.
Also ist die Strucktur mit dem Array schon mal falsch?
Java Code:
Einen generischen Array erzeugen geht in dieser Form nicht. Jaaa, es gibt Tricks und Workarounds, indem man einen leeren Array des passenden Typs oder eben ein passendes Class-Objekt übergeben muss, aber mein Tipp: Nimm eine List, wenn nicht GANZ driftige Gründe dagegen sprechen.
Also solange nicht null übergeben wird kann man den Arraytyp ja per instanceof feststellen mit “if”/“else if”/else". Andernfalls halt nichts generisches und für jeden Arraytyp separat implementieren, ähnlich wie in der Klasse Arrays.
Wenn du primitive Datentypen in generischen Klassen verwenden möchtest, dann musst du die Wrapper-Klassen (Integer, Double, etc… ) verwenden. Arrays von primitiven Datentypen hingegen können direkt verwendet werden.
Falls du ein generisches Array erzeugen möchtest, kannst du Class<T> type = ... T[] array = java.lang.reflect.Array.newInstane(type, a.length);verwenden. Allerdings benötigst du dafür eine Class-Instanz des Typs, die du dir wohl von außen reingeben lassen musst, da es zur Laufzeit nicht möglich ist zu bestimmen, von welchem generischen Typ T nun wirklich ist.
[QUOTE=Natac]Wenn du primitive Datentypen in generischen Klassen verwenden möchtest, dann musst du die Wrapper-Klassen (Integer, Double, etc… ) verwenden. Arrays von primitiven Datentypen hingegen können direkt verwendet werden.
Falls du ein generisches Array erzeugen möchtest, kannst du Class<T> type = ... T[] array = java.lang.reflect.Array.newInstane(type, a.length);verwenden. Allerdings benötigst du dafür eine Class-Instanz des Typs, die du dir wohl von außen reingeben lassen musst, da es zur Laufzeit nicht möglich ist zu bestimmen, von welchem generischen Typ T nun wirklich ist.[/QUOTE]Ich bin mir nicht sicher was dabei raus kommt, aber das geht afaik auch z.B. mit
@SuppressWarnings "unchecked"
Class<T> ttype = (Class<T>) type;```
Hab das jetzt auch nicht ausprobiert. Welchen Typ "type" nun annehmen muss, kann man wie gesagt mit instanceof feststellen.
```public <T> T[] doSomething(T[] anything) {
Class<?> type = null;
if(anything instanceof int[]) {
type = int.class;
}
// esle if fuer restliche primitive und Object (also insgesamt 9)
@SuppressWarnings "unchecked"
Class<T> ttype = (Class<T>) type;
// ... per Reflection in Array wandeln und zurueck geben
}```
@Spacerat : Prinzipiell scheinst du davon auszugehen, dass die möglichen Typen für T der generischen Klasse bekannt sind (wenn du mit instanceof arbeitest). Eine Einschränkung, die ich nicht machen würde. Ich hatte eher an folgendes gedacht:
private Class<T> type;
public MyGenericClass(Class<T> type){
this.type = type;
}
//...
}```
```public MyIntegerClass extends MyGenericClass<Integer>{
public MyIntegerClass(){
super(Integer.class);
}
//...
}```
In der Klasse, in der du den generischen Typ festlegst, übergibst du auch die entsprechende Class-Instanz. Dadurch hast du zur Laufzeit maximale Flexibilität. Und wie schon schlingel sagte, ist das der gängige Weg in Java.
[QUOTE=Natac]@Spacerat : Prinzipiell scheinst du davon auszugehen, dass die möglichen Typen für T der generischen Klasse bekannt sind (wenn du mit instanceof arbeitest). Eine Einschränkung, die ich nicht machen würde.[/QUOTE]Hehe… Prinzipiell hast du Recht. Aber wieso würdest du das so nicht machen? Ich mein das jetzt nicht böse oder so, aber überleg dir mal, wieso die Staffel an "instanceof"s nicht größer wird als 9. Ganz einfach! 8 Primitive und der Rest Object, wo ist da die Einschränkung?. Ich hingegen würde mir solche Konstrukte, wie du sie vorschlägst weiträumig sparen, denn wann braucht man die Klasse als Typ schon mal wirklich? Wenn man ihn braucht, will man meist nur den Typen korrekt bestimmen können um SupressWarnings zu umgehen. Dieses vorhaben aber scheitert genau daran, dass “Class” selber auch generisch ist. Sich deswegen den Typen in einer unendlichen Menge an Klassen zu merken, ist ebenfalls sinnlos. Ich denke mal, was Schlingel mit dem gängigen Weg in Java meinte, ist folgendes (wird er uns sicher aber selbst noch sagen):
return (T[]) Array.newInstance(type, lengths);
}```Ists nicht schön, wie gut es plötzlich funktioniert? Sollte man evtl. die entsprechende Arraymethode ein wenig umschreiben oder geht das aus Kompatibilitätsgründen gar nicht? Ähnlich kann man auch TypeErrors bei "System.arrayCopy()" umgehen. Ein kleiner Wermutstropfen aber bleibt - versuch das mal mit mehrdimensionalen Arrays.
Naja, wenn du eine Instanz von T hast, kannst du dir natürlich über getClass() den Typen geben lassen. Ist allerdings etwas “unsicher”, da die Instanz ja von einem “spezielleren” Typ sein kann, als der generische Parameter. Die saubere Lösung ist schon, die Klasse mitzugeben. Ob, und wenn ja in welchem Umfang man das dann wirklich braucht, hängt vom Anwendungsfall ab, den wir ja hier nicht kennen.
Prinzipiell sollte man aber eher mit Collections arbeiten, wenn man in einem so hohen Maße generisch sein möchte. Dann noch mit Arrays arbeiten zu wollen ist als würde ich meinen alten Golf tunen wollen, statt mir gleich nen Ferrari zu kaufen. Geht, ist aber umständlich (wie wir sehen) und komplizierter.
Für dieses Beispiel sollte doch auch folgender Weg möglich sein (ungetestet, aber mal ein Beispiel von einem anderen Thread von hier):
protected Class<T> clazzOfT;
protected T item;
public MyGenericClass(){
this.clazzOfT = (Class<T>) ((ParameterizedType) clazz).getActualTypeArguments()[0];
this.item = clazzOfT.newInstance();
}
//...
}```
```public MyIntegerClass extends MyGenericClass<Integer>{
public MyIntegerClass(){
super();
}
//...
}```
Das funktioniert natürlich nur, wenn genau ein mal vererbt wird. Sollte von `MyIntegerClass` vererbt werden, so fliegt eine Exception, oder es kommt die falsche Klasse zurück, sofern `MyIntegerClass` auch generisch gemacht wird. Ausserdem hat man die Einschränkungen von `newInstance()`, welche einen paramaterlosen public Konstruktor erwartet.
[QUOTE=Natac]Naja, wenn du eine Instanz von T hast, kannst du dir natürlich über getClass() den Typen geben lassen. Ist allerdings etwas “unsicher”, da die Instanz ja von einem “spezielleren” Typ sein kann, als der generische Parameter.[/QUOTE]Keine Einwände dagegen. Aber ob das in “Array.newInstance()” überhaupt auffällt oder gefragt wird, ist doch das Entscheidende. Der Instanzierungsvorgang geschieht zumindest auf nativer Seite. Kein Plan, wie die das da machen, aber es funktioniert.
Naja, Array.newInstance(...) bekommt ja eine Class-Instanz von genau dem Typ, von dem das Array sein soll. Problematisch könnte folgendes werden:
private final T item;
public GenericClass(final T item) {this.item = item;}
public T[] asArray() {
final T[] array = (T[]) Array.newInstance(this.item.getClass(), 1); // Was bei item == null?
array[0] = this.item;
return array;
}
public static void main(final String[] args) {
final GenericClass<Number> gcn = new GenericClass<Number>(42);
final Number[] array = gcn.asArray();
array[0] = 43L; // java.lang.ArrayStoreException
}
}```
[quote=freezly]Das funktioniert natürlich nur, wenn genau ein mal vererbt wird. Sollte von MyIntegerClass vererbt werden, so fliegt eine Exception, oder es kommt die falsche Klasse zurück, sofern MyIntegerClass auch generisch gemacht wird. Ausserdem hat man die Einschränkungen von newInstance(), welche einen paramaterlosen public Konstruktor erwartet.[/quote]Das Stimmt. Aber das ist aus der Klassenstruktur nicht ersichtlich. Und ein Konzept, dass mir dann zur Laufzeit einen Fehler wirft halte ich nicht für empfehlenswert. Erst recht nicht, da dieser Ansatz per se die Vererbung einschränkt. Und heute die Annahme zu treffen, dass "man das eh nicht braucht" halte ich für sehr gewagt (um das mal vorsichtig auszudrücken ;) )
Also mit null oder void geht das natürlich nicht. Aber dann kämen auch nur noch zwei drei mal “instanceof” hinzu und man gibt entweder null zurück oder schmeisst 'ne Exception.
Ich zumindest musste nie irgendwo die generischen Typen explizit speichern und mir fällt auch nach wie vor kein Anwendungsfall dafür ein. Das was man damit verhindern will, lässt sich jedenfalls nicht verhindern - SupressWarnings.