Die Java Sprachspezifikation definiert einen rohen Typ wie folgt:
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 RohtypsR
, der nicht von einer Superklasse oder einer Superschnittstelle vonR
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.
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.
<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 TypList<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 einenList<String>
an einen Parameter vom TypList
übergeben können, können Sie ihn nicht an einen Parameter vom TypList<Object>
übergeben. Es gibt Subtypisierungsregeln für Generika, undList<String>
ist ein Subtyp des BasistypsList
, jedoch nicht des parametrisierten TypsList<Object>
. Infolgedessen verlieren Sie die Typensicherheit, wenn Sie einen unformatierten Typ wieList
verwenden, jedoch nicht, wenn Sie einen parametrisierten Typ wieList<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.
<?>
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.
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 RohtypsC
, der nicht von seinen Superklassen oder Superschnittstellen geerbt wird, ist der Rohtyp, der der Löschung seines Typs im entspricht generische Deklaration entsprechendC
.
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 wies
und den Löschungen aller ins
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.)
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 .
Leider gibt es zwei Ausnahmen, bei denen Rohtypen in neuem Code verwendet werden müssen, da Java Generika nicht verifiziert sind:
List.class
, nicht List<String>.class
instanceof
Operand, z.B. o instanceof Set
, nicht o instanceof Set<String>
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:
Object
, das in Collection
gespeichert ist, muss besetzt werden, bevor es verwendet werden kannObject
.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
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 Object
s. 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.
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
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.
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.
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>();
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)
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 eineStrict
type Referenced Variable vonArrayList
referenziert.
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 eineraw
type referenzierte Variable verwiesen.
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.
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
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 int
s.
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 int
s 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.
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).
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>();
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();
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 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
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 ...
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.