2009-09-03 17 views
7

E.G. eine Arraylist von Strings müssen wir etwas tun, wieWarum unterstützt Java Typinferenz für Konstruktoren nicht?

List<String> list = new ArrayList<String>(); 

zu schaffen, während es in der Lage sein sollte, den Parametertyp für den Konstruktor zu schließen, so dass wir nur

List<String> list = new ArrayList(); 

Warum eintippen kann nicht Der Typ wird auf die gleiche Weise eingegeben wie Typ-Parameter für generische Methoden.

+4

Gibt es einen Zweck zu fragen "Warum kann Sprache X Y nicht enthalten?"? Die Antwort lautet normalerweise "weil es nicht dazu bestimmt war". – skaffman

+1

Warum? Oh warum! Das ist eine meiner größten Beschwerden über die Generika-Implementierung in Java. Das Wrappen des Konstruktors in einer statischen Factory-Methode bewirkt, dass die Typinferenz wie ein Charm wirkt, also warum nicht mit dem Konstruktor! –

+0

@skaffman: stimmt, aber das Verwirrende ist, dass Typinferenz für parametrisierte Methoden existiert, so dass die Regeln und die Komplexität der Implementierung bereits existieren. Nur nicht für Objekt-Instanziierung! –

Antwort

22

Dies ist eine Java 7-Verbesserung, die auch als Diamantoperator bekannt ist. Die Syntax lautet:

List<String> strings = new ArrayList<>(); 

Der offizielle Vorschlag, accepted for inclusion in Project Coin ist Improved Type Inference for Generic Instance Creation

Nach Rémi Forax, die Änderung bereits im Mercurial-Repository ist.

+0

Obwohl dies gut zu wissen ist, beantwortet es nicht die Frage, warum die aktuelle Version * dies nicht unterstützt. –

+0

@Joachim Sauer: Ich kann keine definitive Antwort geben, warum, aber durch das Lesen der Fehlerberichte, auf die der Diamond-Vorschlag verweist, kann ich sehen, dass die Lösung im Java 5-Zeitrahmen nicht gut verstanden wurde. Heck, Generika sind ein wenig ausgebohrt, auch ohne Konstruktorinferenz in Java 5. –

+3

@Joachim ... Ich glaube, der Satz, den du suchst, ist "Design-Aufsicht". –

2

Es kann sein und es ist eine Funktion für die Aufnahme in JDK7 geplant.

1

Der Typ kann abgeleitet werden, aber die Autoren haben gerade entschieden, dass es besser ist, keine Typinferenz zu haben, als in einigen Fällen eine begrenzte Inferenz.

Wenn Sie Inferenz auf jvm eingeben möchten, überprüfen Sie scala.

+1

Das Problem ist, dass es eine Art Schlussfolgerung gibt! Typparameter auf parametrisierten Methoden sind gut geeignet! Warum können nicht die gleichen Regeln auf die Objekterstellung angewendet werden? –

6

Wie andere gesagt haben, ist dies on the list for Java 7. Ich möchte jedoch darauf hinweisen, dass die Google Collections Library bereits dies für verschiedene Sammlungen unterstützt, wenn Sie gerne statische Importe verwenden. Zum Beispiel schreibe ich oft Code wie:

List<String> list = newArrayList(); 

Alles was Sie brauchen die statische Import und den Raum zwischen new und ArrayList() :)

(Die statische Import in die Lists Klasse wäre entfernen, BTW . Es gibt ähnliche Methoden für Karten etc.)

+4

Ich persönlich finde das sehr hässlich. :) – Bombe

+4

Es ist seltsam, wenn Sie es zuerst sehen, aber wenn Sie daran gewöhnt sind, kann es deutlich Unordnung reduzieren. –

+0

+1. Ich benutze dies, ohne in diesen Tagen zu denken, weil Eclipse den Import beim Autokomplettieren einfügt, und ich habe Google Collections auf meinem Standard-Build-Pfad. – finnw

2

Abgesehen von JDK7 Features, ich vermute, so können Sie erweitert und Super verwenden.

class Animal {} 
class Dog extends Animal {} 

List<? extends Animal> anims = new ArrayList<Dog>(); 
List<? super Dog> superdogs = new ArrayList<Animal>(); 

Sie würden nicht in diesen beiden Fällen ableiten können.

+0

Typ-Inferenz würde nur verwendet werden, wenn Sie es nicht manuell angegeben haben (genau wie es jetzt mit getippten Methoden ist), also würde es das nicht unmöglich machen. –

2

Sie wollen einen Grund, den das aktuelle Java nicht unterstützt.

Ich kann nur sagen, dass Java in der Regel nur kleine Schritte unternimmt. Ich würde vermuten, dass es einen kleinen technischen Fehler gab, dass sie nicht sicher waren, ob sie "Richtig" vor Java 7 bekommen sollten - wahrscheinlich etwas damit zu tun, absolut sicher zu sein, dass es keinen mehrdeutigen Fall in irgendeinem älteren oder nicht-generischen Code erzeugen würde .

Beachten Sie, wie Robert wies darauf hin, dass die Syntax dieser sein wird:

List<String> strings = new ArrayList<>(); 

Beachten Sie die leere <>? Ich vermute, das ist, um diese Art von Schlussfolgerung aus älteren nicht-generischen Code zu disambiguieren; es ist wahrscheinlich nur etwas, an das sie zuerst nicht gedacht haben.

+0

Yeh, ich habe gerade Roberts Links gelesen und das <> ist von rohen Typen zu unterscheiden, sagst du. – Tarski

+0

Interessant, dass diese Art der umgekehrten Richtung in C#, wo der explizite Typ auf der rechten Seite ist und stattdessen der Typ der Variablen genommen wird. Beachten Sie, dass Sie in der C# - Implementierung auch Rückgabetypen aus anderen Methodenaufrufen ableiten können, ohne den Typ explizit definieren zu müssen. var strings = neue ArrayList (); Ich muss hinzufügen, dass ich zunächst nicht so sehr für das var-Schlüsselwort in C#, aber je mehr ich es zu verwenden und zusammen mit Typ-Inferenz von Generika und anonymen Typen wird alles sehr zusammenhängend. – jpierson

0

Ich bin kein Java-Experte, also bin ich mir nicht ganz sicher, was ich sagen werde. Hier sind meine Gedanken:

Da Java Generics durch Löschen implementiert, gibt es für jeden generischen Typ einen zugrunde liegenden unformatierten Typ. Wenn Sie einen generischen Typ definieren, wird ein zugrunde liegender unformatierter Typ verwendet, der rundherum Object verwendet.

Wenn Sie einen neuen ArrayList instanziiert, wäre es falsch, für Compiler den Typ-Parameter aus der Instanziierung Klasse (ArrayList<String> in Ihrem Beispiel) zu schließen, da es eine Klasse mit genau diesem Namen ist und kein Typ-Parameter (dh die Rohtyp, ArrayList). Ich denke auch, dass dies der Grund ist, warum Sie in Java 7 <> zum Aufruf des Konstruktors hinzufügen müssen, um dem Compiler mitzuteilen, dass er den Typ ableitet.

Man könnte argumentieren, dass der Compiler den Raw-Typ nur instanziieren sollte, wenn die Definitionsklasse der Raw-Typ ist, aber ich denke, dass es verwirrend wäre. Ich denke, dass der Compiler von unvollständigen Ausdrücken ableiten muss, die ohne gegebenen Kontext ungültig wären, was für die new ArrayList()-Anweisung nicht der Fall ist.

Ich hoffe, das ist klar, und wenn ich falsch liege, kann mich jemand korrigieren.


Randbemerkung:

Auch hüte dich, dass die rohe Klasse ist nicht der gleiche wie der Typ Object als Typ-Parameter verwendet:

List<String> list = new ArrayList(); 

gültig ist, wo als

List<String> list = new ArrayList<Object>(); 

ist nicht. Im ersten Fall kann der Raw-Typ verwendet werden, als ob er ein generischer Typ wäre, aber im zweiten Fall fragen Sie nach Kontravarianz, die nicht verfügbar ist (nicht, wenn Sie keine Platzhalter verwenden).

+0

Ich wollte diese Frage beantworten, weil ich denke, dass keine der Antworten (die alle exzellent sind!) Hier wirklich die erste Frage anspricht, die * warum * ist :) – Philippe

Verwandte Themen