Wie funktioniert Java die Nutzung Ort Varianz zu C # 's Erklärung Website Varianz vergleichen?

StackOverflow https://stackoverflow.com/questions/4231305

  •  26-09-2019
  •  | 
  •  

Frage

Mein verstehen ist, dass in C # für Generika Varianz Angabe bei der Typdeklaration Ebene geschieht: wenn Sie Ihren generischen Typen erstellen, Sie die Varianz für die Typargumente angeben. In Java, auf der anderen Seite, die Varianz ist angegeben, wo ein allgemeiner verwendet wird. Wenn Sie eine Variable einiger generischen Typ zu erstellen, geben Sie, wie seine Art Argumente variieren

Was sind die Vor- und Nachteile jeder Option?

War es hilfreich?

Lösung

Ich werde nur die Unterschiede zwischen Erklärung Ort zu beantworten und der Nutzung vor Ort Varianz, da, während C # und Java-Generika in vielen anderen Möglichkeiten unterscheiden, diese Unterschiede meist orthogonal zu Varianz.

Zunächst einmal, wenn ich mich richtig erinnere verwenden Ort Varianz ist streng leistungsstärker als Erklärung Ort Varianz (obwohl auf Kosten der Prägnanz) oder zumindest Java Platzhalter sind (die eigentlich stärker sind als die Verwendung vor Ort Varianz) . Diese erhöhte Leistung ist besonders nützlich für Sprachen, in denen Stateful Konstrukte stark verwendet werden, wie C # und Java (aber Scala viel weniger so, zumal seine Standardlisten sind unveränderlich). Betrachten List<E> (oder IList<E>). Da hat es Methoden für beide Zugabe von Es und bekommen E ist, ist es in Bezug auf E unveränderlich ist, und so Deklaration Ort Varianz nicht verwendet werden kann. Doch mit Einsatz-Ort-Varianz kann man nur sagen, List<+Number> die kovariante Teilmenge von List und List<-Number> bekommen die kontraTeilMenge von List zu erhalten. In einer Erklärung vor Ort Sprache würde der Designer der Bibliothek müssen separate Schnittstellen machen für jede Untergruppe (oder Klassen, wenn Sie mehrfache Vererbung von Klassen erlauben) und haben List diese Schnittstellen zu erweitern. Wenn die Bibliothek Designer dieses (beachten Sie, dass C # 's IEnumerable macht nur einen kleinen Teil des covariant Teil IList) nicht tun, dann bist du kein Glück, und Sie haben die gleichen Probleme greifen Sie in einer Sprache zu tun haben, ohne jede Art von Varianz.

So, das die Vorteile der Nutzung Ort Vererbung über Erklärung Ort Erbe ist. Der Vorteil der Deklaration Ort Vererbung über Vererbung-Website ist im Grunde Prägnanz für den Benutzer (sofern der Designer durch die Anstrengung ging jede Klasse / Schnittstelle in seine kovarianten und kontra Teile der Trennung). Für so etwas wie IEnumerable oder Iterator, es ist schön, nicht zu haben Kovarianz jedes einzelne Mal, wenn Sie die Schnittstelle verwenden zu spezifizieren. Java machte diese besonders ärgerlich, durch eine langwierige Syntax (mit Ausnahme von bivariance für die Java-Lösung ideal ist im Grunde genommen).

Natürlich sind diese beiden Sprachfunktionen nebeneinander bestehen können. Für Typ-Parameter, die natürlich kovarianten oder kontra (wie in IEnumerable / Iterator) sind, so erklären, die in der Erklärung. Für Typ-Parameter, die natürlich invariant (wie in (I)List) sind, zu erklären, welche Art von Varianz Sie jedes Mal, wenn Sie es verwenden. Nur nicht eine Verwendung vor Ort Varianz für Argumente mit einer Erklärung Ort Varianz angeben, wie die Dinge nur verwirrend macht.

Es gibt andere Detailfragen Ich habe nicht in gegangen (wie, wie Platzhalter sind tatsächlich mächtiger als Einsatz-Ort-Varianz), aber ich hoffe, Ihre Frage damit beantwortet, um Ihre Inhalte. Ich gebe zu, ich bin auf den Einsatz vor Ort Varianz voreingenommen, aber ich versuchte, die wichtigsten Vorteile von beiden zu schildern, die mit Programmierern in meinen Gesprächen kommen haben und mit Sprachforscher.

Andere Tipps

scheinen die meisten Menschen Erklärung Ort Varianz zu bevorzugen, weil es einfacher für Benutzer macht der Bibliothek (während es ein bisschen schwieriger für die Bibliothek Entwickler machen, obwohl ich, dass der Bibliothek Entwickler argumentieren würde hat über Varianz zu denken, unabhängig davon, wo die Varianz tatsächlich geschrieben.)

Aber bedenken Sie, dass weder Java noch C # sind Beispiele für gutes Sprachdesign.

Während Java bekomme Varianz direkt und unabhängig von der JVM zu arbeiten, weil die kompatibelen VM Verbesserungen in Java 5 und Typ-Löschung, der Nutzung vor Ort Varianz Nutzung eines schwerfälliges Bit macht und die spezielle Implementierung des Typs -erasure hat gezogen wohlverdiente Kritik.

C # 's Modell der Erklärung Ort Varianz nimmt die Last von dem Benutzer der Bibliothek, aber während ihrer Einführung verdinglichten Generika sie im Grunde die Varianz Regeln in denen ihre VM gebaut. Auch heute sind sie wegen der nicht vollständig Mit- / Kontra dieser Fehler unterstützen (und die nicht rückwärtskompatibel Einführung der verdinglichten Collection-Klassen hat die Programmierer in zwei Lager gespalten).

Dies stellt eine schwierige Beschränkung auf allen Sprachen die CLR-Targeting und ist ein Grund, warum alternative Programmiersprachen sind viel lebendiger auf der JVM, obwohl es scheint, dass die CLR „viel schönes Feature“ hat.

Schauen wir uns Scala : Scala ist eine vollständig objektorientierte, funktionale Hybrid auf der JVM läuft. Sie verwenden Typ Löschung wie Java, aber sowohl die Implementierung von Generika und die (Erklärung-site) Varianz sind leichter zu verstehen, einfacher und leistungsstärker als Java (oder C # 's), weil die VM verhängen keine Regeln, wie Varianz zu Arbeit. Die Scala-Compiler prüfen die Varianz Notationen und unsolide Quellcode ablehnen bei der Kompilierung anstelle von Ausnahmen zur Laufzeit zu werfen, während die resultierenden .class-Dateien nahtlos von Java verwendet werden können.

Ein Nachteil der Erklärung Website Varianz ist, dass es scheint Typinferenz härter in einigen Fällen zu machen.

Zur gleichen Zeit kann Scala primitive Typen verwenden, ohne sie in Sammlungen wie in C # Boxen durch die @specialized Annotation verwendet, die den Scala-Compiler sagt eine oder mehr zusätzliche Implementierungen einer Klasse oder Methode auf dem primitive Art angefordert spezialisiert zu erzeugen.

Scala kann „fast“ verdinglichen Generika auch durch Manifest mit der sie die generischen Typen zur Laufzeit wie in C # abrufen kann.

Nachteile von Java-Stil Generika

Eine Folge davon ist, dass die Java-Version nur mit Referenztypen arbeitet (oder boxed Wert-Typ) und nicht wertTypen. IMO das ist der größte Nachteil, da sie hohe Leistung Generika in vielen Szenarien verhindert und erfordern eine manuelle Schreiben von spezialisierten Arten.

Sie stellen keine unveränderliche garantieren wie „Diese Liste enthält nur Objekte vom Typ x“ und Bedürfnisse Laufzeitprüfungen bei jedem Getter. Der generische Typ wirklich existiert.

Wenn Reflexion verwenden Sie können keine Instanz eines generischen Objekts stellen, die generischen Parameter hat.

Die Vorteile von Java-Stil Generika

Sie erhalten Varianz / können zwischen verschiedenen generischen Parameter werfen.

Java: Use-Website Varianz Generika da Java 5. Gebrochene covariant Arrays mit einer anderen Syntax seit 1.0. Keine Laufzeittypinformationen von Generika.

C #: Use-Website Varianz Generika, da C # 2.0. Hinzugefügt Erklärung Website Varianz in C # 4.0. Unterbrochene kovariante Arrays mit einer anderen Syntax da 1,0 (identisch Problem zu Java). „Verdinglicht“ Generika diese Art info bedeutet nicht bei der Kompilierung verloren.

Scala: Sowohl Nutzung Ort / Erklärung Ort Varianz seit Anfang Versionen der Sprache (zumindest seit 2008). Arrays sind keine eigenständige Sprache-Funktion, so dass Sie die gleichen Generika verwenden Syntax und Art Varianz Regeln. Bestimmte Sammlungen werden auf VM-Ebene mit JVM-Arrays implementiert, so dass Sie eine gleiche oder bessere Laufzeitleistung erhalten im Vergleich zu Java-Code.

Um dies näher auszuführen auf dem C # / Java-Array-Typ Sicherheitsproblem: Sie können einen Hund werfen [] zu einem Haustiere [] und eine Katze hinzufügen und einen Laufzeitfehler auslösen, das nicht bei der Kompilierung gefangen wird. Scala implementiert dies richtig.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top