103 Stimmen

Warum sollte es mich interessieren, dass Java keine verifizierten Generika hat?

Dies wurde kürzlich in einem Interview als Frage gestellt, die ich dem Kandidaten gestellt habe und die er sich für die Java-Sprache gewünscht hätte. Es ist allgemein bekannt, dass es als störend empfunden wird, dass Java keine reifizierten Generika hat, aber als ich genauer nachfragte, konnte der Kandidat mir eigentlich nicht sagen, welche Art von Dingen er hätte erreichen können, wären sie vorhanden.

Offensichtlich können aufgrund der zulässigen Raw-Typen in Java (und unsicherer Überprüfungen) die Generika umgangen werden und es kann sich so ergeben, dass eine List (zum Beispiel) tatsächlich Strings enthält. Dies könnte offensichtlich unmöglich gemacht werden, wenn Typinformationen reif wären; aber es muss mehr geben als das!

Könnten Personen Beispiele posten von Dingen, die sie wirklich tun würden, wenn reifizierte Generika verfügbar wären? Ich meine, offensichtlich könnten Sie den Typ einer List zur Laufzeit erhalten - aber was würden Sie damit tun?

public  void foo(List l) {
   if (l.getGenericType() == Integer.class) {
       //yeah baby! err, what now?

BEARBEITEN: Ein schnelles Update zu diesem Thema, da die Antworten hauptsächlich darauf abzielen, dass die Notwendigkeit besteht, eine Class als Parameter zu übergeben (zum Beispiel EnumSet.noneOf(TimeUnit.class)). Mir ging es mehr darum, etwas in der Art aufzuzeigen wo dies einfach nicht möglich ist. Zum Beispiel:

List l1 = api.gimmeAList();
List l2 = api.gimmeAnotherList();

if (l1.getGenericType().isAssignableFrom(l2.getGenericType())) {
    l1.addAll(l2); //warum um alles in der Welt würde ich das überhaupt tun?

14voto

Cogman Punkte 1890

Die Serialisierung wäre mit Reifizierung einfacher. Was wir wollen ist

deserialize(ding, List.class);

Was wir tun müssen ist

deserialize(ding, new TypeReference>(){});

sieht hässlich aus und funktioniert eigenartig.

Es gibt auch Fälle, in denen es wirklich hilfreich wäre, etwas wie

public  void doThings(List ding) {
    if (T instanceof Q)
      doCrazyness();
  }

zu sagen. Diese Dinge beißen nicht oft, aber wenn sie passieren, dann beißen sie.

11voto

sateesh Punkte 26553

Meine Erfahrung mit Java Generics ist ziemlich begrenzt, und abgesehen von den Punkten, die andere Antworten bereits erwähnt haben, gibt es ein Szenario, das im Buch Java Generics and Collections von Maurice Naftalin und Philip Walder erklärt wird, in dem die verifizierten Generics nützlich sind.

Da die Typen nicht verifizierbar sind, ist es nicht möglich, parametrierte Ausnahmen zu haben.

Zum Beispiel ist die folgende Form der Deklaration ungültig.

class ParametericException extends Exception // Kompilierfehler

Dies liegt daran, dass die catch-Klausel überprüft, ob die geworfene Ausnahme mit einem bestimmten Typ übereinstimmt. Diese Überprüfung entspricht dem gleichen Vorgang wie der Instanztest, und da der Typ nicht verifizierbar ist, ist die obige Form der Aussage ungültig.

Wenn der obige Code gültig wäre, wäre eine Ausnahmebehandlung auf folgende Weise möglich gewesen:

try {
     throw new ParametericException(42);
} catch (ParametericException e) { // Kompilierfehler
  ...
}

Das Buch erwähnt auch, dass eine Definition von Java Generics ähnlich der Definition von C++ Templates (Erweiterung) zu einer effizienteren Implementierung führen kann, da dies mehr Möglichkeiten für Optimierungen bietet. Es bietet jedoch keine Erklärung darüber hinaus, daher wären Erläuterungen von sachkundigen Personen hilfreich.

8voto

Hank Gay Punkte 67607

Arrays würden wahrscheinlich viel besser mit Generics umgehen, wenn sie reifiziert wären.

5voto

James B Punkte 3632

Ich habe einen Wrapper, der ein JDBC-ResultSet als Iterator darstellt (das bedeutet, dass ich Datenbank-basierte Operationen viel einfacher durch Dependency Injection testen kann).

Die API sieht so aus: Iterator, wobei T ein Typ ist, der nur durch Strings im Konstruktor konstruiert werden kann. Der Iterator betrachtet dann die aus der SQL-Abfrage zurückgegebenen Strings und versucht sie mit einem Konstruktor des Typs T abzugleichen.

Aufgrund der aktuellen Implementierung von Generics muss ich auch die Klasse der Objekte angeben, die ich aus meinem ResultSet erstellen werde. Wenn ich es richtig verstehe, wenn Generics verifiziert wären, könnte ich einfach T.getClass() aufrufen, seine Konstruktoren erhalten und dann das Ergebnis von Class.newInstance() nicht mehr casten müssen, was viel ordentlicher wäre.

Im Grunde genommen denke ich, dass das Schreiben von APIs (im Gegensatz zum Schreiben einer Anwendung) einfacher wird, weil man viel mehr aus Objekten ableiten kann und dadurch weniger Konfiguration erforderlich ist... Ich habe die Auswirkungen von Annotationen nicht geschätzt, bis ich sie in Dingen wie Spring oder XStream gesehen habe, anstatt endloser Konfigurationen.

5voto

kvb Punkte 54045

Eine schöne Sache wäre es, das Verboxen für primitive (Wert-)Typen zu vermeiden. Dies hängt etwas mit der Kritik an Arrays zusammen, die andere erhoben haben, und in Fällen, in denen der Speicherplatz begrenzt ist, könnte dies tatsächlich einen signifikanten Unterschied machen.

Es gibt auch mehrere Arten von Problemen beim Schreiben eines Frameworks, bei denen die Möglichkeit, über den parametrisierten Typ zu reflektieren, wichtig ist. Natürlich kann dies umgangen werden, indem ein Klassenobjekt zur Laufzeit übergeben wird, dieses jedoch verschleiert die API und belastet den Benutzer des Frameworks zusätzlich.

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