2008-08-24 11 views
19

Ich habe eine Java-Funktion definiert:Warum kann ich das type-Argument nicht explizit an eine generische Java-Methode übergeben?

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

Ein Weg, es ist wie so zu nennen:

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

Warum nicht explizit kann ich es nenne durch den generischen Typ Argument übergeben? :

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

Ich bekomme den Fehler Illegal start of expression vom Compiler.

+1

Cheekysoft erklärt, warum, aber wenn Sie wirklich das Bedürfnis verspüren, den zweiten Typ def hinzufügen, fügen Sie einfach den Klassennamen vor dem statischen Funktionsaufruf: Liste myList = MyClass. createEmptyList(); –

Antwort

28

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

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

Für nicht-statische Methoden können Sie das Schlüsselwort this verwenden: ' Objektliste = das. emptyList(); ' – Roland

1

Es war eine ganze Weile, da ich in jene Teile von Java gegraben, aber ...

Warum Sie nicht tun können, es war wahrscheinlich durch die Sprache Entwickler eine Design-Wahl. Aufgrund der von Java verwendeten type erasure werden die Generika-Informationen trotzdem zur Kompilierungszeit gelöscht. In Ihrem Beispiel würde sie also genau denselben Byte-Code erzeugen, unabhängig davon, ob Sie den Typparameter hatten oder nicht.

22

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 die gleiche Art und Weise genericised werden, dass ein Typ kann, so dass die einzige Option für ein Verfahren mit einem dynamisch typisierte generischen Rückgabetyp - puh, dass ein Schluck :-) ist - ist in weitergeben der Typ als Argument.

Für eine wirklich hervorragende FAQ zu Java-Generika, see Angelika Langer's generics FAQ.

.
.

Follow-up:

Es wäre nicht sinnvoll, in diesem Zusammenhang macht das Array-Argument wie in Collection.toArray(T[]) zu verwenden. Der einzige Grund dafür, dass ein Array verwendet wird, besteht darin, dass das gleiche (vorab zugewiesene) Array verwendet wird, um die Ergebnisse zu enthalten (wenn das Array groß genug ist, um alle zu berücksichtigen). Dies spart die ständige Zuweisung eines neuen Arrays zur Laufzeit.

jedoch für die Zwecke der Bildung, wenn Sie die Array Typisierung verwenden wollen, 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 ]); 
} 
+1

-1 Dies ist ein häufiges Missverständnis, dass ein Klassenliteral in 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 in [Xaviers Antwort] erwähnte Syntax (http://stackoverflow.com/a/25877). Jedenfalls gibt es, wie [Henriks Antwort] (http://stackoverflow.com/a/24996) erwähnt, keinen wirklichen Anwendungsfall, um die Typparameter eines neuen generischen Objekts anzugeben, wenn es sofort einer Variablen zugewiesen wird - nur der Typ von Diese Variable ist von nun an wichtig, sogar zur Kompilierzeit. Das ist der Grund für die <> 'Syntax von Java 7. –

+0

Sie verwenden nicht den Parameter 'type', also sollten Sie ihn nicht übergeben – newacct

0

@pauldoo Ja, Sie haben recht. Es ist eine der Schwächen mit den Java-Generika Imho.

ich Cheekysoft response würde Ich mag auch vorschlagen, zu prüfen, wie es durch die Java Menschen getan wird sich, wie T [] AbstractCollection#toArray (T [] a). Ich denke, Cheekysoft Version ist überlegen, aber die Java-Version hat den Vorteil der Vertrautheit.

Bearbeiten: Link hinzugefügt. Re-edit: Gefunden einen Fehler auf SO :)


Follow-up auf Cheekysoft: Nun, da es eine Liste von irgendeiner Art, die das entsprechende Beispiel zurückgegeben werden sollte sollte wie etwas aussehen:

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

Aber ja, das Klassenobjekt ist eindeutig das bessere. Mein einziges Argument ist das der Vertrautheit, und in genau diesem Fall ist es nicht viel wert (in der Tat ist es schlecht).

Verwandte Themen