web-dev-qa-db-de.com

Was ist ein Rohtyp und warum sollten wir ihn nicht verwenden?

Fragen:

  • Was sind RAW-Typen in Java und warum höre ich oft, dass sie nicht in neuem Code verwendet werden sollten?
  • Was ist die Alternative, wenn wir keine Rohtypen verwenden können, und wie ist es besser?
603

Was ist ein Rohtyp?

Die Java Sprachspezifikation definiert einen rohen Typ wie folgt:

JLS 4.8 Raw Types

Ein roher Typ ist definiert als einer von:

  • Der Referenztyp, der gebildet wird, indem der Name einer generischen Typdeklaration ohne zugehörige Typargumentliste verwendet wird.

  • Ein Array-Typ, dessen Elementtyp ein Rohtyp ist.

  • Ein nicht static Elementtyp eines Rohtyps R, der nicht von einer Superklasse oder einer Superschnittstelle von R geerbt wird.

Hier ist ein Beispiel zur Veranschaulichung:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

Hier ist MyType<E> ein parametrisierter Typ ( JLS 4.5 ). Es ist üblich, diesen Typ umgangssprachlich einfach als MyType zu bezeichnen, aber technisch ist der Name MyType<E>.

mt hat einen unformatierten Typ (und generiert eine Kompilierungswarnung) am ersten Aufzählungspunkt in der obigen Definition. inn hat auch einen rohen Typ ab dem dritten Aufzählungspunkt.

MyType.Nested ist kein parametrisierter Typ, obwohl es ein Elementtyp eines parametrisierten Typs ist. MyType<E>, weil es static ist.

mt1 und mt2 werden beide mit aktuellen Typparametern deklariert, sodass es sich nicht um unformatierte Typen handelt.


Was ist das Besondere an Rohtypen?

Grundsätzlich verhalten sich Rohtypen genauso wie vor der Einführung von Generika. Das heißt, das Folgende ist zum Zeitpunkt der Kompilierung völlig legal.

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

Der obige Code funktioniert einwandfrei, aber nehmen wir an, Sie haben auch Folgendes:

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    Java.lang.Boolean cannot be cast to Java.lang.String

Jetzt treten zur Laufzeit Probleme auf, da names etwas enthält, das kein instanceof String ist.

Vermutlich, wenn Sie names nur String enthalten möchten, können Sie könnte vielleicht noch einen rohen Typ verwenden und überprüfen Sie manuell jedenadd Sie selbst und dann manuell besetzen zu String jedem Gegenstand aus names. Noch besser ist es jedoch, KEINEN rohen Typ zu verwenden und den Compiler die ganze Arbeit für Sie erledigen zu lassen und die Kraft von Java Generika.

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

Natürlich, wenn Sie [~ # ~] tun [~ # ~] wollen, dass names ein Boolean zulässt, dann können Sie es als List<Object> names deklarieren, und das Der obige Code würde kompilieren.

Siehe auch


Wie unterscheidet sich ein Raw-Typ von der Verwendung von <Object> als Typparameter?

Das Folgende ist ein Zitat aus Effective Java 2nd Edition, Punkt 23: Verwenden Sie keine rohen Typen in neuem Code:

Was ist der Unterschied zwischen dem Rohtyp List und dem parametrisierten Typ List<Object>? Ersteres hat die generische Typprüfung losgelöst, während letzteres dem Compiler ausdrücklich mitteilte, dass er Objekte aller Art aufnehmen kann. Während Sie einen List<String> an einen Parameter vom Typ List übergeben können, können Sie ihn nicht an einen Parameter vom Typ List<Object> übergeben. Es gibt Subtypisierungsregeln für Generika, und List<String> ist ein Subtyp des Basistyps List, jedoch nicht des parametrisierten Typs List<Object>. Infolgedessen verlieren Sie die Typensicherheit, wenn Sie einen unformatierten Typ wie List verwenden, jedoch nicht, wenn Sie einen parametrisierten Typ wie List<Object> verwenden.

Betrachten Sie zur Veranschaulichung die folgende Methode, die einen List<Object> verwendet und eine new Object() anfügt.

void appendNewObject(List<Object> list) {
   list.add(new Object());
}

Generika in Java sind unveränderlich. Ein List<String> ist kein List<Object>, daher würde Folgendes eine Compiler-Warnung generieren:

List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!

Wenn Sie appendNewObject deklariert hätten, einen unformatierten Typ List als Parameter zu verwenden, würde dies kompiliert, und Sie würden daher die Typensicherheit verlieren, die Sie von Generika erhalten.

Siehe auch


Wie unterscheidet sich ein roher Typ von der Verwendung von <?> als Typparameter?

List<Object>, List<String> usw. sind alle List<?>, daher kann es verlockend sein, nur zu sagen, dass sie nur List sind. Es gibt jedoch einen großen Unterschied: Da ein List<E> nur add(E) definiert, können Sie einem List<?> nicht einfach ein beliebiges Objekt hinzufügen. Da der rohe Typ List keine Typensicherheit hat, können Sie add für einen List so ziemlich alles tun.

Betrachten Sie die folgende Variation des vorherigen Snippets:

static void appendNewObject(List<?> list) {
    list.add(new Object()); // compilation error!
}
//...

List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!

Der Compiler hat hervorragende Arbeit geleistet, um Sie davor zu schützen, die Typinvarianz des List<?> zu verletzen! Wenn Sie den Parameter als unformatierten Typ List list deklariert hätten, würde der Code kompiliert und Sie würden die Typinvariante von List<String> names verletzen.


Ein roher Typ ist die Löschung dieses Typs

Zurück zu JLS 4.8:

Es ist möglich, als Typ das Löschen eines parametrisierten Typs oder das Löschen eines Array-Typs zu verwenden, dessen Elementtyp ein parametrisierter Typ ist. Ein solcher Typ heißt roher Typ.

[...]

Die Superklassen (bzw. Superschnittstellen) eines Rohtyps sind die Löschungen der Superklassen (Superschnittstellen) einer beliebigen Parametrisierung des generischen Typs.

Der Typ eines Konstruktors, einer Instanzmethode oder eines Nicht-static -Felds eines Rohtyps C, der nicht von seinen Superklassen oder Superschnittstellen geerbt wird, ist der Rohtyp, der der Löschung seines Typs im entspricht generische Deklaration entsprechend C.

Einfacher ausgedrückt, wenn ein roher Typ verwendet wird, werden die Konstruktoren, Instanzmethoden und nicht-static -Felder auch gelöscht.

Nehmen Sie das folgende Beispiel:

class MyType<E> {
    List<String> getNames() {
        return Arrays.asList("John", "Mary");
    }

    public static void main(String[] args) {
        MyType rawType = new MyType();
        // unchecked warning!
        // required: List<String> found: List
        List<String> names = rawType.getNames();
        // compilation error!
        // incompatible types: Object cannot be converted to String
        for (String str : rawType.getNames())
            System.out.print(str);
    }
}

Wenn wir raw MyType verwenden, wird getNames ebenfalls gelöscht, so dass es raw List zurückgibt!

JLS 4.6 erklärt weiterhin Folgendes:

Die Typlöschung ordnet auch die Signatur eines Konstruktors oder einer Methode einer Signatur zu, die keine parametrisierten Typen oder Typvariablen enthält. Die Löschung einer Konstruktor- oder Methodensignatur s ist a Signatur bestehend aus dem gleichen Namen wie s und den Löschungen aller in s angegebenen formalen Parametertypen.

Der Rückgabetyp einer Methode und die Typparameter einer generischen Methode oder eines generischen Konstruktors werden ebenfalls gelöscht, wenn die Signatur der Methode oder des Konstruktors gelöscht wird.

Das Löschen der Signatur einer generischen Methode hat keine Typparameter.

Der folgende Fehlerbericht enthält einige Gedanken von Maurizio Cimadamore, einem Compiler-Entwickler, und Alex Buckley, einem der Autoren des JLS, warum diese Art von Verhalten auftreten sollte: https://bugs.openjdk.Java .net/browse/JDK-6400189 . (Kurz gesagt, es vereinfacht die Spezifikation.)


Wenn es unsicher ist, warum darf man einen Rohtyp verwenden?

Hier ist ein weiteres Zitat aus JLS 4.8:

Die Verwendung von Raw-Typen ist nur als Zugeständnis für die Kompatibilität von Legacy-Code zulässig. Von der Verwendung von Raw-Typen in Code, der nach der Einführung der Generizität in die Programmiersprache Java geschrieben wurde, wird dringend abgeraten. Es ist möglich, dass zukünftige Versionen der Programmiersprache Java die Verwendung von RAW-Typen nicht zulassen.

Effective Java 2nd Edition hat auch folgendes hinzuzufügen:

Warum haben die Sprachdesigner diese Typen zugelassen, da Sie keine Rohtypen verwenden sollten? Kompatibilität gewährleisten.

Die Plattform Java begann ihr zweites Jahrzehnt, als Generika eingeführt wurden, und es gab eine enorme Menge von Java Code, der keine Generika verwendete. Es wurde als kritisch erachtet, dass dieser gesamte Code legal und mit neuem Code, der Generika verwendet, interoperabel bleibt. Es musste legal sein, Instanzen von parametrisierten Typen an Methoden zu übergeben, die für die Verwendung mit normalen Typen entwickelt wurden, und umgekehrt. Diese Anforderung, bekannt als Migrationskompatibilität, führte zur Entscheidung, Rohtypen zu unterstützen.

Zusammenfassend gesagt sollten RAW-Typen NIE in neuem Code verwendet werden. Verwenden Sie immer parametrierte Typen .


Gibt es keine Ausnahmen?

Leider gibt es zwei Ausnahmen, bei denen Rohtypen in neuem Code verwendet werden müssen, da Java Generika nicht verifiziert sind:

  • Klassenliterale, z.B. List.class, nicht List<String>.class
  • instanceof Operand, z.B. o instanceof Set, nicht o instanceof Set<String>

Siehe auch

697

Was sind RAW-Typen in Java und warum höre ich oft, dass sie nicht in neuem Code verwendet werden sollten?

Rohtypen sind eine alte Geschichte der Java Sprache. Am Anfang gab es Collections und sie hielten Objects nicht mehr und nicht weniger. Jede Operation an Collections erforderte Casts von Object bis zum gewünschten Typ.

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

Während dies die meiste Zeit funktionierte, sind Fehler aufgetreten

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

Die alten typenlosen Sammlungen konnten die Typensicherheit nicht erzwingen, sodass der Programmierer sich merken musste, was er in einer Sammlung gespeichert hatte.
Generika wurden erfunden, um diese Einschränkung zu umgehen. Der Entwickler deklarierte den gespeicherten Typ einmal und der Compiler tat es stattdessen.

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

Zum Vergleich:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

Komplexer die vergleichbare Schnittstelle:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

Beachten Sie, dass es unmöglich ist, die Schnittstelle CompareAble mit compareTo(MyCompareAble) mit Raw-Typen zu implementieren. Warum sollten Sie sie nicht verwenden:

  • Jedes Object, das in Collection gespeichert ist, muss besetzt werden, bevor es verwendet werden kann
  • Die Verwendung von Generika ermöglicht die Überprüfung der Kompilierungszeit
  • Die Verwendung von RAW-Typen entspricht dem Speichern der einzelnen Werte als Object.

Was der Compiler macht: Generics sind abwärtskompatibel, sie verwenden die gleichen Klassen Java wie die Raw-Typen. Die Magie geschieht meistens zur Kompilierungszeit.

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

Wird kompiliert als:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

Dies ist derselbe Code, den Sie schreiben würden, wenn Sie die Rohtypen direkt verwenden würden. Obwohl ich nicht sicher bin, was mit der CompareAble Schnittstelle passiert, denke ich, dass sie zwei compareTo Funktionen erzeugt, von denen eine eine MyCompareAble und die andere eine Object aufnimmt und übergibt es zum ersten nach dem Gießen.

Was sind die Alternativen zu Rohtypen: Verwenden Sie Generika

58
josefx

Ein roher Typ ist der Name einer generischen Klasse oder Schnittstelle ohne Typargumente. Beispiel für die generische Box-Klasse:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Um einen parametrisierten Typ von Box<T> zu erstellen, geben Sie ein tatsächliches Typargument für den formalen Typparameter T an:

Box<Integer> intBox = new Box<>();

Wenn das eigentliche Typargument weggelassen wird, erstellen Sie einen Basistyp von Box<T>:

Box rawBox = new Box();

Daher ist Box der Basistyp des generischen Typs Box<T>. Ein nicht generischer Klassen- oder Schnittstellentyp ist jedoch kein Basistyp.

Raw-Typen werden im Legacy-Code angezeigt, da viele API-Klassen (z. B. die Collections-Klassen) vor JDK 5.0 nicht generisch waren. Bei der Verwendung von RAW-Typen tritt im Wesentlichen ein Verhalten vor Generika auf - ein Box gibt Ihnen Objects. Aus Gründen der Abwärtskompatibilität ist es zulässig, seinem Raw-Typ einen parametrisierten Typ zuzuweisen:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

Wenn Sie jedoch einem parametrisierten Typ einen Rohtyp zuweisen, erhalten Sie eine Warnung:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

Sie erhalten auch eine Warnung, wenn Sie einen Rohtyp verwenden, um generische Methoden aufzurufen, die im entsprechenden generischen Typ definiert sind:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

Die Warnung zeigt, dass RAW-Typen generische Typprüfungen umgehen und den Fang von unsicherem Code auf die Laufzeit verschieben. Daher sollten Sie die Verwendung von Rohtypen vermeiden.

Der Abschnitt Type Erasure enthält weitere Informationen darüber, wie der Compiler Java RAW-Typen verwendet.

Ungeprüfte Fehlermeldungen

Wie bereits erwähnt, können beim Mischen von Legacy-Code mit generischem Code Warnmeldungen ähnlich den folgenden auftreten:

Hinweis: Example.Java verwendet ungeprüfte oder unsichere Vorgänge.

Hinweis: Mit -Xlint neu kompilieren: Deaktiviert für Details.

Dies kann passieren, wenn eine ältere API verwendet wird, die auf Rohtypen ausgeführt wird, wie im folgenden Beispiel gezeigt:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

Der Begriff "deaktiviert" bedeutet, dass der Compiler nicht über genügend Typinformationen verfügt, um alle zur Gewährleistung der Typensicherheit erforderlichen Typprüfungen durchzuführen. Die "ungeprüfte" Warnung ist standardmäßig deaktiviert, obwohl der Compiler einen Hinweis gibt. Um alle "ungeprüften" Warnungen anzuzeigen, kompilieren Sie erneut mit -Xlint: ungeprüft.

Durch erneutes Kompilieren des vorherigen Beispiels mit -Xlint: unmarkiert werden die folgenden zusätzlichen Informationen angezeigt:

WarningDemo.Java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<Java.lang.Integer>
        bi = createBox();
                      ^
1 warning

Um ungeprüfte Warnungen vollständig zu deaktivieren, verwenden Sie das Flag -Xlint: -unchecked. Die Annotation @SuppressWarnings("unchecked") unterdrückt ungeprüfte Warnungen. Wenn Sie mit der @SuppressWarnings -Syntax nicht vertraut sind, lesen Sie Anmerkungen.

Ursprüngliche Quelle: Java Tutorials

24
Adelin
 private static List<String> list = new ArrayList<String>();

Sie sollten den Typparameter angeben.

Die Warnung weist darauf hin, dass Typen, die zur Unterstützung von generics definiert sind, parametrisiert werden sollten, anstatt ihre Rohform zu verwenden.

List ist zur Unterstützung von Generika definiert: public class List<E>. Dies ermöglicht viele typsichere Operationen, die zur Kompilierzeit überprüft werden.

19
Bozho

Ein "raw" -Typ in Java ist eine Klasse, die nicht generisch ist und sich mit "raw" -Objekten befasst, anstatt mit typsicheren generischen Typparametern.

Bevor beispielsweise Java Generics verfügbar waren, würden Sie eine Auflistungsklasse wie die folgende verwenden:

LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);

Wenn Sie ein Objekt zur Liste hinzufügen, ist es egal, um welchen Objekttyp es sich handelt. Wenn Sie es aus der Liste abrufen, müssen Sie es explizit in den Typ umwandeln, den Sie erwarten.

Bei Verwendung von Generika entfernen Sie den "unbekannten" Faktor, da Sie explizit angeben müssen, welcher Objekttyp in die Liste aufgenommen werden kann:

LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);

Beachten Sie, dass Sie bei Generika das vom get-Aufruf kommende Objekt nicht umwandeln müssen. Die Auflistung ist so vordefiniert, dass sie nur mit MyObject funktioniert. Gerade diese Tatsache ist der Haupttreiber für Generika. Es ändert eine Quelle von Laufzeitfehlern in etwas, das zur Kompilierzeit überprüft werden kann.

16
Andy White

Hier betrachte ich mehrere Fälle, durch die Sie das Konzept klarstellen können

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

Fall 1

ArrayList<String> arr Es handelt sich um eine ArrayList-Referenzvariable mit dem Typ String, die auf ein ArralyList-Objekt vom Typ String verweist. Dies bedeutet, dass nur ein Objekt vom Typ String enthalten sein kann.

Es ist ein strikter zu String kein roher Typ, daher wird niemals eine Warnung ausgegeben.

    arr.add("hello");// alone statement will compile successfully and no warning.

    arr.add(23);  //prone to compile time error.
     //error: no suitable method found for add(int)

Fall 2

In diesem Fall ist ArrayList<String> arr ein strenger Typ, aber Ihr Objekt new ArrayList(); ist ein roher Typ.

    arr.add("hello"); //alone this compile but raise the warning.
    arr.add(23);  //again prone to compile time error.
    //error: no suitable method found for add(int)

hier arr ist ein strikter Typ. Wenn Sie also einen integer hinzufügen, tritt ein Kompilierungsfehler auf.

Warnung: - Ein Raw Type Object wird auf eine Strict type Referenced Variable von ArrayList referenziert.

Fall 3

In diesem Fall ist ArrayList arr ein unformatierter Typ, aber Ihr Objekt new ArrayList<String>(); ist ein strenger Typ.

    arr.add("hello");  
    arr.add(23);  //compiles fine but raise the warning.

Es wird ein beliebiger Objekttyp hinzugefügt, da arr ein Raw-Typ ist.

Warnung: - Ein Strict Type Object wird auf eine raw type referenzierte Variable verwiesen.

12
Vikrant Kashyap

Der Compiler möchte, dass Sie Folgendes schreiben:

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

andernfalls können Sie list einen beliebigen Typ hinzufügen, wodurch die Instanziierung als new ArrayList<String>() sinnlos wird. Java Generika sind nur ein Feature zur Kompilierungszeit, daher akzeptiert ein mit new ArrayList<String>() erstelltes Objekt gerne Integer - oder JFrame -Elemente, wenn es einer Referenz des "raw" -Elementes zugewiesen wird Typ "List - Das Objekt selbst weiß nichts darüber, welche Typen es enthalten soll, nur der Compiler.

12

Was ist ein roher Typ und warum höre ich oft, dass sie nicht in neuem Code verwendet werden sollten?

Ein "roher Typ" ist die Verwendung einer generischen Klasse, ohne ein (e) Typargument (e) für ihren (seine) parametrisierten Typ (en) anzugeben, z. Verwenden von List anstelle von List<String>. Bei der Einführung von Generics in Java wurden mehrere Klassen aktualisiert, um Generics zu verwenden. Die Verwendung dieser Klasse als "unformatierter Typ" (ohne Angabe eines Typarguments) ermöglichte es dem Legacy-Code, weiterhin kompiliert zu werden.

"Raw-Typen" werden aus Gründen der Abwärtskompatibilität verwendet. Ihre Verwendung in neuem Code wird nicht empfohlen, da die Verwendung der generischen Klasse mit einem Typargument eine stärkere Typisierung ermöglicht, wodurch die Verständlichkeit des Codes verbessert und potenzielle Probleme früher erkannt werden können.

Was ist die Alternative, wenn wir keine Rohtypen verwenden können und wie ist es besser?

Die bevorzugte Alternative besteht darin, generische Klassen wie beabsichtigt zu verwenden - mit einem geeigneten Typargument (z. B. List<String>). Auf diese Weise kann der Programmierer die Typen genauer spezifizieren, zukünftigen Betreuern mehr Informationen über die beabsichtigte Verwendung einer Variablen oder Datenstruktur geben und dem Compiler die Möglichkeit geben, eine bessere Typensicherheit durchzusetzen. Diese Vorteile können zusammen die Codequalität verbessern und helfen, die Einführung einiger Codierungsfehler zu verhindern.

Zum Beispiel für eine Methode, bei der der Programmierer sicherstellen möchte, dass eine List-Variable namens 'names' nur Strings enthält:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error
11
Bert F

Ein raw - Typ ist das Fehlen eines type-Parameters bei Verwendung eines generischen Typs.

Raw-Type sollte nicht verwendet werden, da dies zu Laufzeitfehlern führen kann, z. B. das Einfügen eines double in einen Set von ints.

Set set = new HashSet();
set.add(3.45); //ok

Wenn Sie das Material aus Set abrufen, wissen Sie nicht, was herauskommt. Nehmen wir an, Sie erwarten, dass alles ints ist. Sie wandeln es in Integer um. Ausnahme zur Laufzeit, wenn double 3.45 erscheint.

Wenn ein Typparameter zu Ihrem Set hinzugefügt wird, wird sofort ein Kompilierungsfehler angezeigt. Mit diesem präventiven Fehler können Sie das Problem beheben, bevor zur Laufzeit etwas in die Luft springt (was Zeit und Mühe spart).

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
8
Lars Andren

Hier ist ein weiterer Fall, in dem Rohtypen Sie beißen werden:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<String> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Compiles
    value1 = withGeneric.getSomethingElse();

    // Produces compile error:
    // incompatible types: Java.lang.Object cannot be converted to Java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

Wie in der akzeptierten Antwort erwähnt, verlieren Sie die Unterstützung für Generika im Code des Rohtyps. Jeder Typparameter wird in seine Löschung konvertiert (die im obigen Beispiel nur Object ist).

6
GuyPaddock

Was sagt, ist, dass Ihr list ein List von nicht spezifizierten Objekten ist. Das heißt, dass Java nicht weiß, welche Art von Objekten in der Liste enthalten sind. Wenn Sie dann die Liste durchlaufen möchten, müssen Sie jedes Element umwandeln, um auf die Eigenschaften dieses Elements (in diesem Fall String) zugreifen zu können.

Im Allgemeinen ist es besser, die Sammlungen zu parametrisieren, damit Sie keine Konvertierungsprobleme haben. Sie können nur Elemente des parametrisierten Typs hinzufügen, und Ihr Editor bietet Ihnen die geeigneten Methoden zur Auswahl an.

private static List<String> list = new ArrayList<String>();
5
pakore

Tutorial-Seite .

Ein roher Typ ist der Name einer generischen Klasse oder Schnittstelle ohne Typargumente. Beispiel für die generische Box-Klasse:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Um einen parametrisierten Box-Typ zu erstellen, geben Sie ein tatsächliches Typargument für den formalen Typparameter T an:

Box<Integer> intBox = new Box<>();

Wenn das Argument für den tatsächlichen Typ weggelassen wird, erstellen Sie einen unformatierten Box-Typ:

Box rawBox = new Box();
4

Vermeiden Sie Rohtypen

Rohtypen beziehen sich auf die Verwendung eines generischen Typs ohne Angabe eines Typparameters.

Zum Beispiel ,

Eine Liste ist ein roher Typ, während List<String> ein parametrisierter Typ ist.

Bei der Einführung von Generics in JDK 1.5 wurden Raw-Typen nur beibehalten, um die Abwärtskompatibilität mit älteren Java-Versionen zu gewährleisten. Obwohl die Verwendung von Rohtypen weiterhin möglich ist,

Sie sollten vermieden werden :

  • Sie erfordern normalerweise Abgüsse
  • Sie sind nicht typsicher und einige wichtige Fehler treten nur zur Laufzeit auf
  • Sie sind weniger aussagekräftig und dokumentieren sich nicht wie parametrisierte Typen selbst. Beispiel

    import Java.util.*;
    
    public final class AvoidRawTypes {
    
    void withRawType() {
    
        //Raw List doesn't self-document, 
        //doesn't state explicitly what it can contain
    
        List stars = Arrays.asList("Arcturus", "Vega", "Altair");
    
        Iterator iter = stars.iterator();
    
        while (iter.hasNext()) {
    
            String star = (String) iter.next(); //cast needed
    
            log(star);
        }
    
    }
    
    void withParameterizedType() {
    
        List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
    
        for (String star: stars) {
    
            log(star);
        }
    
    }
    
    private void log(Object message) {
    
        System.out.println(Objects.toString(message));
    
    }
    
    }
    

Als Referenz : https://docs.Oracle.com/javase/tutorial/Java/generics/rawTypes.html

1
Ashish

Ich fand diese Seite, nachdem ich einige Beispielübungen gemacht hatte und genau das gleiche Rätsel hatte.

=============================================================

public static void main(String[] args) throws IOException {

    Map wordMap = new HashMap();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

===================== Zu diesem Code ========================

public static void main(String[] args) throws IOException {
    // replace with TreeMap to get them sorted by name
    Map<String, Integer> wordMap = new HashMap<String, Integer>();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
        Entry<String, Integer> entry =   i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

}

================================================ ============================

Es mag sicherer sein, aber es dauerte 4 Stunden, um die Philosophie zu entwirren ...

1
user2442615

Raw-Typen sind in Ordnung, wenn sie das ausdrücken, was Sie ausdrücken möchten.

Beispielsweise gibt eine Deserialisierungsfunktion möglicherweise List zurück, kennt jedoch den Elementtyp der Liste nicht. List ist hier also der passende Rückgabetyp.

0
Stefan Reich