PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java Generics


Monger
2005-07-07, 18:20:19
Seid JDK 5.0 gibt es ja in Java die Generics. Ich hab mich durch die Neuerung von 5.0 ein bißchen durchgearbeitet und auch etwas geübt, aber viele Fragen bleiben immer noch offen...

Zum Beispiel:


Vector<MeinObjekt> vector = new Vector<MeinObjekt>();

Klar, ich instanziiere einen Vector aus Objekten des Typs "Mein Objekt".


HashMap<MeinKey, MeinValue> hash = new HashMap<MeinKey, MeinValue>();


Jetzt frage ich mich: Was legt denn fest, wann mal einer, mal mehrere Generics definiert werden? Denn an der Stelle ist ja noch gar nicht klar, dass ich eine Methode mit zwei Parametern aufrufen will. Was zu der Frage führt: Woher weiß denn eine Klasse, was sie mit solchen Angaben anfangen soll?
Angenommen ich wollte eine eigene Klasse à la HashMap machen, wie kann ich die denn dazu bringen, Generics richtig zu verwenden?

HellHorse
2005-07-07, 18:49:25
Du kannst die Typparameter bei der Klassendefinition angeben:

public class MySuperGenericStuff<A, B, C> {
...
}

Vector (http://java.sun.com/j2se/1.5.0/docs/api/java/util/Vector.html)
HashMap (http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashMap.html)

Und gefälligst keine Vektoren verwenden und gegen Interfaces programmieren :biggrin:

Monger
2005-07-07, 18:55:17
Du kannst die Typparameter bei der Klassendefinition angeben:

public class MySuperGenericStuff<A, B, C> {
...
}

Vector (http://java.sun.com/j2se/1.5.0/docs/api/java/util/Vector.html)
HashMap (http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashMap.html)

Und gefälligst keine Vektoren verwenden und gegen Interfaces programmieren :biggrin:

Thx. Es kann manchmal so simpel sein...

Noch eine Frage: Was heißt denn das hier?

addAll(Collection<? extends E> c)

Ist eine Methode des Vectors. Was bedeutet denn das Fragezeichen? Ich hab das auch schon in den Tutorials gesehen, hab aber die Erklärung dafür wohl übersehen.

PH4Real
2005-07-07, 19:16:09
'?' stellt eine Wildcard dar.

Sprich, in diesem <? extends E> beinhaltet alle Objekte, die vom gleichen oder geerbt von Typ E sind. E gibt in diesem Fall die Objekte an, die sich schon in der Collection befinden (sieht man an Vector<E> ).

Es gibt auch noch nur <?> oder <? super E> oder auch komplizierter als Returnwert von min aus Collections (mein Lieblingsbeispiel ;) ):
static <T extends Object & Comparable<? super T>> T

Siehe auch: http://www.galileocomputing.de/openbook/javainsel4/javainsel_06_012.htm#Rxx365java06012040001D41F0321EF als kleine Erklärung, wobei es bestimmt bessere gibt.

PS: Benutz lieber ArrayList als Vector ;).

Monger
2005-07-08, 12:44:20
Noch hakt es verständnismäßig ein bißchen...

Wenn ich Wildcards verwende. darf ich dann mischen? Wohl nicht, oder?

Eine Wildcard heißt nur, dass ich nicht GENAU den selben Typ reinstopfen muss, sondern auch eine Klasse die davon ableitet. Aber darf ich das nicht immer?

Zum Beispiel:


class Beispiel<T>{
public void set(<T> arg0){}
}

// ...

Beispiel<Number> beispiel = new Beispiel<Number>();
beispiel.set(new Integer(5));


Das geht doch auch, oder? Wo liegt der Vorteil der Wildcard? Weil wenn ich z.B. in einen Vector mal eine Number, mal Integer, mal Float reinstecke, kann der Compiler sich auch nur die Oberklasse merken, oder? Wenn ich aus dem Vector alle Objekte wieder raushole, kann er mir nur sagen dass sie vom Typ Number sind.

Und last but not least: Welchen Sinn könnte es denn machen, alle Oberklassen per <? super Beispiel> zuzulassen, aber nicht alle Unterklassen?

HellHorse
2005-07-08, 13:24:48
Das wie und warum zu Wildcards und generics von dem Typen der dafür mitverantwortlich ist: Gilad Bracha
http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

Monger
2005-07-28, 08:34:38
Mir ist da noch ein Gedanke gekommen auf den ich keine Antwort weiß:

Angenommen ich habe eine Klasse "Animal", und eine Klasse "Dog" die von ersterer erbt.
Jetzt will ich eine Methode haben, mit der jedes Tier seinen Elternteil setzen kann. Also z.B.


class Animal{
private Animal parent;
public void setParent(Animal parent){ this.parent = parent; }
}


Jetzt frage ich mich halt: Ein Hund hat nur einen Hund als Elternteil, und nicht irgendein Tier. Kann ich irgendwie erzwingen, dass in jeder erbenden Klasse von Tier genau die Klasse des eigenen Typs als Parameter gefordert wird? Eine Möglichkeit wäre ja:


class Animal<E>{
private E parent;
public void setParent(E parent){ this.parent = parent; }
}

Das hat aber den Nachteil, dass ein Benutzer einen Hund auch mit

Dog<Cat> fluffy = new Dog<Cat>();

erzeugen kann, und dem Hund dann als Elternteil eine Katze vorsetzen kann. Damit habe ich das eigentliche Problem nur verschoben, und nicht behoben. Gibt es dafür eine elegante Lösung?

HellHorse
2005-07-28, 09:28:32
Sowas? :ugly:
public abstract class Animal<A extends Animal>{
public abstract A mate(A mate);
}

public class Dog extends Animal<Dog> {
public Dog mate(Dog mate) {
return new Dog(this, mate)
}
}

Ja, die Namen sind shice :usad:

Monger
2005-07-28, 10:26:28
Sowas? :ugly:


Ja, genau sowas. Irgendwie saß ich der grottigen Meinung auf, dass generische Parameter vererbt werden. Aber so funktioniert das ganze natürlich wunderbar... :D

Wie ich grad ausprobiert habe, kann man das Spielchen ja sogar weiter treiben, um auch Unterarten zuzulassen:

public class Dog<D extends Dog> extends Animal<D> {

// hab in der Oberklasse ein Attribut "mate" eingeführt
@Override
public void setMate(D mate) {
this.mate = mate;
}
}

Cool! :ugly: