31 Stimmen

Warum kann ich das Typ-Argument nicht explizit an eine generische Java-Methode übergeben?

Ich habe eine Java-Funktion definiert:

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

Eine Möglichkeit, dies zu tun, ist die folgende:

List<Integer> myList = createEmptyList(); // Compiles

Warum kann ich es nicht aufrufen, indem ich das Argument des generischen Typs explizit übergebe? :

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

Ich erhalte die Fehlermeldung Illegal start of expression des Compilers.

1 Stimmen

Cheekysoft erklärt warum, aber wenn Sie wirklich das Bedürfnis haben, den zweiten Typ def hinzuzufügen, fügen Sie einfach den Klassennamen vor dem Aufruf der statischen Funktion hinzu: List<Integer> myList = MyClass.<Integer>createEmptyList();

49voto

Wenn der Java-Compiler den Parametertyp für eine statische Methode nicht selbst ableiten kann, können Sie ihn immer mit dem voll qualifizierten Methodennamen übergeben: Klasse . < Typ > Methode();

Object list = Collections.<String> emptyList();

12 Stimmen

Für nicht-statische Methoden können Sie das Schlüsselwort this verwenden: Object list = this.<String> emptyList();

25voto

Cheekysoft Punkte 34104

Sie können, wenn Sie den Typ als Methodenparameter übergeben.

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

Methoden können nicht auf dieselbe Weise generisch gemacht werden wie ein Typ, so dass die einzige Option für eine Methode mit einem dynamisch typisierten generischen Rückgabetyp - puh, das ist ein Zungenbrecher :-) -- ist die Übergabe des Typs als Argument.

Für eine wirklich ausgezeichnete FAQ über Java-Generika, siehe Angelika Langers FAQ zu Generika .

.
.

Nachbereitung:

Es würde in diesem Zusammenhang keinen Sinn machen, das Array-Argument zu verwenden, wie in Collection.toArray( T[] ) . Der einzige Grund, warum dort ein Array verwendet wird, ist, dass dasselbe (vorab zugewiesene) Array verwendet wird, um die Ergebnisse zu enthalten (wenn das Array groß genug ist, um sie alle unterzubringen). Dies erspart das ständige Zuweisen eines neuen Arrays zur Laufzeit.

Wenn Sie jedoch die Array-Typisierung verwenden möchten, ist die Syntax sehr ähnlich:

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}

3 Stimmen

-Dies ist ein weit verbreiteter Irrglaube, dass ein Klassenliteral an eine generische Methode übergeben werden muss, wenn keine anderen Argumente den Compiler auf den generischen Typ schließen lassen. Alles, was wirklich notwendig ist, ist die Syntax, die in Die Antwort von Xavier . Wie auch immer, als Henriks Antwort Es gibt keinen wirklichen Anwendungsfall für die Angabe der Typparameter eines neuen generischen Objekts, wenn es sofort einer Variablen zugewiesen wird - nur der Typ dieser Variablen ist von nun an von Bedeutung, sogar zur Kompilierzeit. Das ist der Grund für Java 7's <> Syntax.

0 Stimmen

Sie verwenden nicht den Parameter type also sollte es einfach nicht passieren

0 Stimmen

Dies führt zu der Warnung "type is never used", so dass es besser ist, die automatische Kompilierung des Typs zuzulassen

0voto

Henrik Gustafsson Punkte 46490

@pauldoo Ja, Sie haben völlig recht. Das ist imho eine der Schwächen der Java-Generika.

Als Antwort auf Cheekysoft möchte ich vorschlagen, auch zu schauen, wie es von den Java-Leuten selbst gemacht wird, wie T[] AbstractCollection#toArray (T[] a). Ich denke, Cheekysofts Version ist besser, aber die Java-Version hat den Vorteil der Vertrautheit.

Edit: Link hinzugefügt. Re-edit: Einen Fehler auf SO gefunden :)


Folgemaßnahmen zu Cheekysoft: Nun, da es sich um eine Liste irgendeines Typs handelt, die zurückgegeben werden soll, sollte das entsprechende Beispiel etwa so aussehen:

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

Aber ja, die Übergabe des Klassenobjekts ist eindeutig die bessere Lösung. Mein einziges Argument ist das der Vertrautheit, und genau in diesem Fall ist es nicht viel wert (eigentlich ist es sogar schlecht).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X