Java 什么是原始类型,为什么我们不应该使用它?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2770321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is a raw type and why shouldn't we use it?
提问by polygenelubricants
Questions:
问题:
- What are raw types in Java, and why do I often hear that they shouldn't be used in new code?
- What is the alternative if we can't use raw types, and how is it better?
- Java 中的原始类型是什么,为什么我经常听到他们不应该在新代码中使用?
- 如果我们不能使用原始类型,有什么替代方法,它如何更好?
回答by Andy White
A "raw" type in Java is a class which is non-generic and deals with "raw" Objects, rather than type-safe generic type parameters.
Java 中的“原始”类型是一个非泛型的类,它处理“原始”对象,而不是类型安全的泛型类型参数。
For example, before Java generics was available, you would use a collection class like this:
例如,在 Java 泛型可用之前,您将使用这样的集合类:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
When you add your object to the list, it doesn't care what type of object it is, and when you get it from the list, you have to explicitly cast it to the type you are expecting.
当您将对象添加到列表中时,它并不关心它是什么类型的对象,当您从列表中获取它时,您必须将其显式转换为您期望的类型。
Using generics, you remove the "unknown" factor, because you must explicitly specify which type of objects can go in the list:
使用泛型,您可以删除“未知”因素,因为您必须明确指定可以进入列表的对象类型:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
Notice that with generics you don't have to cast the object coming from the get call, the collection is pre-defined to only work with MyObject. This very fact is the main driving factor for generics. It changes a source of runtime errors into something that can be checked at compile time.
请注意,使用泛型,您不必强制转换来自 get 调用的对象,该集合已预先定义为仅适用于 MyObject。这个事实是泛型的主要驱动因素。它将运行时错误的来源更改为可以在编译时检查的内容。
回答by Bert F
What is a raw type and why do I often hear that they shouldn't be used in new code?
什么是原始类型,为什么我经常听到他们不应该在新代码中使用?
A "raw type" is the use of a generic class without specifying a type argument(s) for its parameterized type(s), e.g. using List
instead of List<String>
. When generics were introduced into Java, several classes were updated to use generics. Using these class as a "raw type" (without specifying a type argument) allowed legacy code to still compile.
“原始类型”是使用泛型类而不为其参数化类型指定类型参数,例如使用List
代替List<String>
。当泛型被引入 Java 时,几个类被更新为使用泛型。使用这些类作为“原始类型”(不指定类型参数)允许遗留代码仍然编译。
"Raw types" are used for backwards compatibility. Their use in new code is not recommended because using the generic class with a type argument allows for stronger typing, which in turn may improve code understandability and lead to catching potential problems earlier.
“原始类型”用于向后兼容。不推荐在新代码中使用它们,因为使用带有类型参数的泛型类允许更强的类型化,这反过来可以提高代码的可理解性并导致更早地发现潜在问题。
What is the alternative if we can't use raw types, and how is it better?
如果我们不能使用原始类型,有什么替代方法,它如何更好?
The preferred alternative is to use generic classes as intended - with a suitable type argument (e.g. List<String>
). This allows the programmer to specify types more specifically, conveys more meaning to future maintainers about the intended use of a variable or data structure, and it allows compiler to enforce better type-safety. These advantages together may improve code quality and help prevent the introduction of some coding errors.
首选的替代方法是按预期使用泛型类 - 带有合适的类型参数(例如List<String>
)。这允许程序员更具体地指定类型,向未来的维护者传达更多关于变量或数据结构的预期用途的含义,并且它允许编译器强制执行更好的类型安全。这些优点一起可以提高代码质量并有助于防止引入一些编码错误。
For example, for a method where the programmer wants to ensure a List variable called 'names' contains only Strings:
例如,对于程序员想要确保名为“names”的 List 变量仅包含字符串的方法:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
回答by Lars Andren
A raw-type is the a lack of a type parameterwhen using a generic type.
甲生型是缺少一个的类型参数使用通用类型时。
Raw-type should not be used because it could cause runtime errors, like inserting a double
into what was supposed to be a Set
of int
s.
不应该使用原始类型,因为它可能会导致运行时错误,例如将 a 插入double
到应该是 aSet
的int
s 中。
Set set = new HashSet();
set.add(3.45); //ok
When retrieving the stuff from the Set
, you don't know what is coming out. Let's assume that you expect it to be all int
s, you are casting it to Integer
; exception at runtime when the double
3.45 comes along.
从 中检索内容时Set
,您不知道会出现什么。让我们假设您希望它全部为int
s,您正在将其转换为Integer
; 当double
3.45 出现时,运行时出现异常。
With a type parameteradded to your Set
, you will get a compile error at once. This preemptive error lets you fix the problem before something blows up during runtime (thus saving on time and effort).
将类型参数添加到您的Set
,您将立即收到编译错误。这种先发制人的错误使您可以在运行时出现问题之前解决问题(从而节省时间和精力)。
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
回答by polygenelubricants
What is a raw type?
什么是原始类型?
The Java Language Specification defines a raw typeas follows:
Java 语言规范定义了一个原始类型,如下所示:
JLS 4.8 Raw Types
JLS 4.8 原始类型
A raw type is defined to be one of:
The reference type that is formed by taking the name of a generic type declaration without an accompanying type argument list.
An array type whose element type is a raw type.
A non-
static
member type of a raw typeR
that is not inherited from a superclass or superinterface ofR
.
原始类型定义为以下之一:
通过采用泛型类型声明的名称而形成的引用类型,而没有随附的类型参数列表。
元素类型为原始类型的数组类型。
未从 的超类或超接口继承
static
的原始类型的非成员类型。R
R
Here's an example to illustrate:
这里有一个例子来说明:
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!)
}
}
Here, MyType<E>
is a parameterized type(JLS 4.5). It is common to colloquially refer to this type as simply MyType
for short, but technically the name is MyType<E>
.
这里,MyType<E>
是一个参数化类型(JLS 4.5)。通常将这种类型通俗地简称MyType
为简称,但从技术上讲,名称是MyType<E>
.
mt
has a raw type (and generates a compilation warning) by the first bullet point in the above definition; inn
also has a raw type by the third bullet point.
mt
上面定义中的第一个要点具有原始类型(并生成编译警告);inn
第三个要点也有一个原始类型。
MyType.Nested
is not a parameterized type, even though it's a member type of a parameterized type MyType<E>
, because it's static
.
MyType.Nested
不是参数化类型,即使它是参数化类型的成员类型MyType<E>
,因为它是static
.
mt1
, and mt2
are both declared with actual type parameters, so they're not raw types.
mt1
, 并且mt2
都使用实际类型参数声明,因此它们不是原始类型。
What's so special about raw types?
原始类型有什么特别之处?
Essentially, raw types behaves just like they were before generics were introduced. That is, the following is entirely legal at compile-time.
本质上,原始类型的行为就像引入泛型之前一样。也就是说,以下在编译时是完全合法的。
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
The above code runs just fine, but suppose you also have the following:
上面的代码运行得很好,但假设您还有以下代码:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
Now we run into trouble at run-time, because names
contains something that isn't an instanceof String
.
现在我们在运行时遇到了麻烦,因为names
包含不是instanceof String
.
Presumably, if you want names
to contain only String
, you couldperhaps still use a raw type and manually check everyadd
yourself, and then manually castto String
every item from names
. Even better, though is NOT to use a raw type and let the compiler do all the work for you, harnessing the power of Java generics.
据推测,如果你想names
仅仅是遏制String
,您可以或许仍然使用原始型和手动检查每一个add
自己,然后手动施放到String
每一个项目从names
。更好的是,不要使用原始类型,而是让编译器为您完成所有工作,利用 Java 泛型的强大功能。
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
Of course, if you DOwant names
to allow a Boolean
, then you can declare it as List<Object> names
, and the above code would compile.
当然,如果你不要想names
允许Boolean
,那么你可以将它声明为List<Object> names
,和上面的代码将编译。
See also
也可以看看
How's a raw type different from using <Object>
as type parameters?
原始类型与<Object>
用作类型参数有何不同?
The following is a quote from Effective Java 2nd Edition, Item 23: Don't use raw types in new code:
以下引用自Effective Java 2nd Edition, Item 23: Don't use raw types in new code:
Just what is the difference between the raw type
List
and the parameterized typeList<Object>
? Loosely speaking, the former has opted out generic type checking, while the latter explicitly told the compiler that it is capable of holding objects of any type. While you can pass aList<String>
to a parameter of typeList
, you can't pass it to a parameter of typeList<Object>
. There are subtyping rules for generics, andList<String>
is a subtype of the raw typeList
, but not of the parameterized typeList<Object>
. As a consequence, you lose type safety if you use raw type likeList
, but not if you use a parameterized type likeList<Object>
.
原始类型
List
和参数化类型之间有什么区别List<Object>
?粗略地说,前者选择退出泛型类型检查,而后者明确告诉编译器它能够保存任何类型的对象。虽然可以将 a 传递List<String>
给 type 的参数List
,但不能将其传递给 type 的参数List<Object>
。泛型有子类型规则,它List<String>
是原始类型的子类型List
,但不是参数化类型的子类型List<Object>
。因此,如果使用类似 的原始类型List
List<Object>
,则会失去类型安全性,但如果使用类似 的参数化类型则不会。
To illustrate the point, consider the following method which takes a List<Object>
and appends a new Object()
.
为了说明这一点,请考虑以下采用 aList<Object>
并附加 a 的方法new Object()
。
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Generics in Java are invariant. A List<String>
is not a List<Object>
, so the following would generate a compiler warning:
Java 中的泛型是不变的。AList<String>
不是 a List<Object>
,因此以下将生成编译器警告:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
If you had declared appendNewObject
to take a raw type List
as parameter, then this would compile, and you'd therefore lose the type safety that you get from generics.
如果您已声明appendNewObject
采用原始类型List
作为参数,那么这将被编译,因此您将失去从泛型中获得的类型安全性。
See also
也可以看看
How's a raw type different from using <?>
as a type parameter?
原始类型与<?>
用作类型参数有何不同?
List<Object>
, List<String>
, etc are all List<?>
, so it may be tempting to just say that they're just List
instead. However, there is a major difference: since a List<E>
defines only add(E)
, you can't add just any arbitrary object to a List<?>
. On the other hand, since the raw type List
does not have type safety, you can add
just about anything to a List
.
List<Object>
, List<String>
, 等等都是List<?>
,所以可能很想说它们只是List
代替。但是,有一个主要区别:由于 aList<E>
只定义了add(E)
,您不能将任意对象添加到 a 中List<?>
。另一方面,由于原始类型List
没有类型安全,您可以add
对List
.
Consider the following variation of the previous snippet:
考虑上一个片段的以下变体:
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
The compiler did a wonderful job of protecting you from potentially violating the type invariance of the List<?>
! If you had declared the parameter as the raw type List list
, then the code would compile, and you'd violate the type invariant of List<String> names
.
编译器在保护您免受潜在违反List<?>
!的类型不变性方面做得非常出色。如果您已将参数声明为原始类型List list
,则代码将被编译,并且您将违反 的类型不变量List<String> names
。
A raw type is the erasure of that type
原始类型是该类型的擦除
Back to JLS 4.8:
回到 JLS 4.8:
It is possible to use as a type the erasureof a parameterized type or the erasure of an array type whose element type is a parameterized type. Such a type is called a raw type.
[...]
The superclasses (respectively, superinterfaces) of a raw type are the erasures of the superclasses (superinterfaces) of any of the parameterizations of the generic type.
The type of a constructor, instance method, or non-
static
field of a raw typeC
that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding toC
.
这是可能作为一种类型使用擦除参数化类型或数组类型,其元素类型是参数化类型的擦除。这种类型称为原始类型。
[...]
原始类型的超类(分别为超接口)是泛型类型的任何参数化的超类(超接口)的擦除。
未从其超类或超接口继承
static
的原始类型的构造函数、实例方法或非字段的类型C
是原始类型,该原始类型对应于对应于 的泛型声明中其类型的擦除C
。
In simpler terms, when a raw type is used, the constructors, instance methods and non-static
fields are also erased.
简单来说,当使用原始类型时,构造函数、实例方法和非static
字段也会被删除。
Take the following example:
以下面的例子为例:
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);
}
}
When we use the raw MyType
, getNames
becomes erased as well, so that it returns a raw List
!
当我们使用 raw 时MyType
,getNames
也会被擦除,因此它返回一个 raw List
!
JLS 4.6continues to explain the following:
JLS 4.6继续解释以下内容:
Type erasure also maps the signature of a constructor or method to a signature that has no parameterized types or type variables.The erasure of a constructor or method signature
s
is a signature consisting of the same name ass
and the erasures of all the formal parameter types given ins
.The return type of a method and the type parameters of a generic method or constructor also undergo erasure if the method or constructor's signature is erased.
The erasure of the signature of a generic method has no type parameters.
类型擦除还将构造函数或方法的签名映射到没有参数化类型或类型变量的签名。构造函数或方法签名的擦除
s
是由与 中s
给出的所有形式参数类型相同的名称和擦除组成的签名s
。如果方法或构造函数的签名被擦除,方法的返回类型和泛型方法或构造函数的类型参数也会被擦除。
泛型方法签名的擦除没有类型参数。
The following bug report contains some thoughts from Maurizio Cimadamore, a compiler dev, and Alex Buckley, one of the authors of the JLS, on why this sort of behavior ought to occur: https://bugs.openjdk.java.net/browse/JDK-6400189. (In short, it makes the specification simpler.)
以下错误报告包含来自编译器开发人员 Maurizio Cimadamore 和 JLS 的作者之一亚历克斯巴克利关于为什么应该发生这种行为的一些想法:https: //bugs.openjdk.java.net/browse /JDK-6400189。(简而言之,它使规范更简单。)
If it's unsafe, why is it allowed to use a raw type?
如果不安全,为什么允许使用原始类型?
Here's another quote from JLS 4.8:
这是 JLS 4.8 中的另一句话:
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.
仅允许使用原始类型作为对遗留代码兼容性的让步。强烈反对在将泛型引入 Java 编程语言之后编写的代码中使用原始类型。Java 编程语言的未来版本可能会禁止使用原始类型。
Effective Java 2nd Editionalso has this to add:
Effective Java 2nd Edition还添加了以下内容:
Given that you shouldn't use raw types, why did the language designers allow them? To provide compatibility.
The Java platform was about to enter its second decade when generics were introduced, and there was an enormous amount of Java code in existence that did not use generics. It was deemed critical that all this code remains legal and interoperable with new code that does use generics. It had to be legal to pass instances of parameterized types to methods that were designed for use with ordinary types, and vice versa. This requirement, known as migration compatibility, drove the decision to support raw types.
鉴于您不应该使用原始类型,为什么语言设计者允许它们?提供兼容性。
当泛型被引入时,Java 平台即将进入第二个十年,并且存在大量没有使用泛型的 Java 代码。所有这些代码都保持合法并且可以与使用泛型的新代码互操作被认为是至关重要的。将参数化类型的实例传递给设计用于普通类型的方法必须是合法的,反之亦然。这一要求,称为迁移兼容性,推动了支持原始类型的决定。
In summary, raw types should NEVER be used in new code. You should always use parameterized types.
总之,原始类型不应该在新代码中使用。您应该始终使用参数化类型。
Are there no exceptions?
没有例外吗?
Unfortunately, because Java generics are non-reified, there are two exceptions where raw types must be used in new code:
不幸的是,因为 Java 泛型是非具体化的,所以在新代码中必须使用原始类型的情况有两个例外:
- Class literals, e.g.
List.class
, notList<String>.class
instanceof
operand, e.g.o instanceof Set
, noto instanceof Set<String>
- 类文字,例如
List.class
, notList<String>.class
instanceof
操作数,例如o instanceof Set
,不是o instanceof Set<String>
See also
也可以看看
回答by josefx
What are raw types in Java, and why do I often hear that they shouldn't be used in new code?
Java 中的原始类型是什么,为什么我经常听到他们不应该在新代码中使用?
Raw-types are ancient history of the Java language. In the beginning there were Collections
and they held Objects
nothing more and nothing less. Every operation on Collections
required casts from Object
to the desired type.
原始类型是 Java 语言的古老历史。一开始有Collections
,他们持有的Objects
不多也不少。对所需类型的每个操作都Collections
将转换Object
为所需的类型。
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
While this worked most of the time, errors did happen
虽然这在大多数情况下都有效,但确实发生了错误
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
The old typeless collections could not enforce type-safety so the programmer had to remember what he stored within a collection.
Generics where invented to get around this limitation, the developer would declare the stored type once and the compiler would do it instead.
旧的无类型集合无法强制类型安全,因此程序员必须记住他在集合中存储的内容。
为了绕过这个限制而发明的泛型,开发人员将声明存储类型一次,而编译器会改为这样做。
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
For Comparison:
比较:
// 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
More complex the Compareable interface:
更复杂的可比较接口:
//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;}
}
Note that it is impossible to implement the CompareAble
interface with compareTo(MyCompareAble)
with raw types.
Why you should not use them:
请注意,使用原始类型实现CompareAble
接口是不可能的compareTo(MyCompareAble)
。为什么不应该使用它们:
- Any
Object
stored in aCollection
has to be cast before it can be used - Using generics enables compile time checks
- Using raw types is the same as storing each value as
Object
Object
存储在 a 中的任何内容Collection
都必须先进行转换才能使用- 使用泛型启用编译时检查
- 使用原始类型与将每个值存储为相同
Object
What the compiler does: Generics are backward compatible, they use the same java classes as the raw types do. The magic happens mostly at compile time.
编译器的作用:泛型向后兼容,它们使用与原始类型相同的 Java 类。魔术主要发生在编译时。
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
Will be compiled as:
将编译为:
List someStrings = new ArrayList();
someStrings.add("one");
String one = (String)someStrings.get(0);
This is the same code you would write if you used the raw types directly. Thought I'm not sure what happens with the CompareAble
interface, I guess that it creates two compareTo
functions, one taking a MyCompareAble
and the other taking an Object
and passing it to the first after casting it.
如果您直接使用原始类型,这与您将编写的代码相同。以为我不确定CompareAble
接口会发生什么,我猜它创建了两个compareTo
函数,一个接受 a MyCompareAble
,另一个接受 anObject
并在转换后将其传递给第一个。
What are the alternatives to raw types: Use generics
原始类型的替代方法是什么:使用泛型
回答by Bozho
private static List<String> list = new ArrayList<String>();
You should specify the type-parameter.
您应该指定类型参数。
The warning advises that types that are defined to support genericsshould be parameterized, rather than using their raw form.
该警告建议定义为支持泛型的类型应该被参数化,而不是使用它们的原始形式。
List
is defined to support generics: public class List<E>
. This allows many type-safe operations, that are checked compile-time.
List
被定义为支持泛型:public class List<E>
. 这允许许多类型安全的操作,在编译时检查。
回答by pakore
What is saying is that your list
is a List
of unespecified objects. That is that Java does not know what kind of objects are inside the list. Then when you want to iterate the list you have to cast every element, to be able to access the properties of that element (in this case, String).
意思是你list
是一个未List
指定的对象。那就是 Java 不知道列表中的对象类型是什么。然后,当您想要迭代列表时,您必须强制转换每个元素,以便能够访问该元素的属性(在本例中为 String)。
In general is a better idea to parametrize the collections, so you don't have conversion problems, you will only be able to add elements of the parametrized type and your editor will offer you the appropiate methods to select.
一般来说,参数化集合是一个更好的主意,因此您不会遇到转换问题,您只能添加参数化类型的元素,并且您的编辑器将为您提供适当的选择方法。
private static List<String> list = new ArrayList<String>();
回答by Michael Borgwardt
The compiler wants you to write this:
编译器希望你这样写:
private static List<String> list = new ArrayList<String>();
because otherwise, you could add any type you like into list
, making the instantiation as new ArrayList<String>()
pointless. Java generics are a compile-time feature only, so an object created with new ArrayList<String>()
will happily accept Integer
or JFrame
elements if assigned to a reference of the "raw type" List
- the object itself knows nothing about what types it's supposed to contain, only the compiler does.
因为否则,您可以将任何您喜欢的类型添加到 中list
,使实例化变得new ArrayList<String>()
毫无意义。Java泛型只是一个编译时特性,所以如果分配给“原始类型”的引用,用它创建的对象new ArrayList<String>()
将很乐意接受Integer
或JFrame
元素List
——对象本身不知道它应该包含什么类型,只有编译器知道。
回答by Adelin
A raw type is the name of a generic class or interface without any type arguments. For example, given the generic Box class:
原始类型是没有任何类型参数的泛型类或接口的名称。例如,给定通用 Box 类:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
To create a parameterized type of Box<T>
, you supply an actual type argument for the formal type parameter T
:
要创建 的参数化类型Box<T>
,请为形式类型参数提供实际类型参数T
:
Box<Integer> intBox = new Box<>();
If the actual type argument is omitted, you create a raw type of Box<T>
:
如果省略实际类型参数,则创建一个原始类型Box<T>
:
Box rawBox = new Box();
Therefore, Box
is the raw type of the generic type Box<T>
. However, a non-generic class or interface type is not a raw type.
因此,Box
是泛型类型的原始类型Box<T>
。但是,非泛型类或接口类型不是原始类型。
Raw types show up in legacy code because lots of API classes (such as the Collections classes) were not generic prior to JDK 5.0. When using raw types, you essentially get pre-generics behavior — a Box
gives you Object
s. For backward compatibility, assigning a parameterized type to its raw type is allowed:
原始类型出现在遗留代码中是因为许多 API 类(例如 Collections 类)在 JDK 5.0 之前不是通用的。使用原始类型时,您基本上会获得预泛型行为 - aBox
给您Object
s。为了向后兼容,允许将参数化类型分配给它的原始类型:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
But if you assign a raw type to a parameterized type, you get a warning:
但是,如果将原始类型分配给参数化类型,则会收到警告:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
You also get a warning if you use a raw type to invoke generic methods defined in the corresponding generic type:
如果使用原始类型调用在相应泛型类型中定义的泛型方法,也会收到警告:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
The warning shows that raw types bypass generic type checks, deferring the catch of unsafe code to runtime. Therefore, you should avoid using raw types.
警告显示原始类型绕过泛型类型检查,将不安全代码的捕获推迟到运行时。因此,您应该避免使用原始类型。
The Type Erasure section has more information on how the Java compiler uses raw types.
类型擦除部分提供了有关 Java 编译器如何使用原始类型的更多信息。
Unchecked Error Messages
未经检查的错误消息
As mentioned previously, when mixing legacy code with generic code, you may encounter warning messages similar to the following:
如前所述,将遗留代码与通用代码混合时,您可能会遇到类似于以下内容的警告消息:
Note: Example.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
注意:Example.java 使用未经检查或不安全的操作。
注意:使用 -Xlint:unchecked 重新编译以获取详细信息。
This can happen when using an older API that operates on raw types, as shown in the following example:
使用对原始类型进行操作的旧 API 时可能会发生这种情况,如下例所示:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
The term "unchecked" means that the compiler does not have enough type information to perform all type checks necessary to ensure type safety. The "unchecked" warning is disabled, by default, though the compiler gives a hint. To see all "unchecked" warnings, recompile with -Xlint:unchecked.
术语“未检查”意味着编译器没有足够的类型信息来执行确保类型安全所需的所有类型检查。默认情况下,“unchecked”警告是禁用的,尽管编译器会给出提示。要查看所有“未检查”警告,请使用 -Xlint:unchecked 重新编译。
Recompiling the previous example with -Xlint:unchecked reveals the following additional information:
使用 -Xlint:unchecked 重新编译前面的示例会显示以下附加信息:
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
To completely disable unchecked warnings, use the -Xlint:-unchecked flag. The @SuppressWarnings("unchecked")
annotation suppresses unchecked warnings. If you are unfamiliar with the @SuppressWarnings
syntax, see Annotations.
要完全禁用未经检查的警告,请使用 -Xlint:-unchecked 标志。该@SuppressWarnings("unchecked")
注释抑制unchecked警告。如果您不熟悉@SuppressWarnings
语法,请参阅注释。
Original source: Java Tutorials
原始来源:Java 教程
回答by user2442615
I found this page after doing some sample exercises and having the exact same puzzlement.
在做了一些示例练习并遇到完全相同的困惑后,我找到了这个页面。
============== I went from this code as provide by the sample ===============
============== 我从示例中提供的代码开始 ================
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());
}
====================== To This 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());
}
}
===============================================================================
================================================== ==============================
It may be safer but took 4 hours to demuddle the philosophy...
这可能更安全,但花了 4 个小时来解释哲学......