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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 12:39:21  来源:igfitidea点击:

What is a raw type and why shouldn't we use it?

javagenericsraw-types

提问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 Listinstead 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 doubleinto what was supposed to be a Setof ints.

不应该使用原始类型,因为它可能会导致运行时错误,例如将 a 插入double到应该是 aSetints 中。

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 ints, you are casting it to Integer; exception at runtime when the double3.45 comes along.

从 中检索内容时Set,您不知道会出现什么。让我们假设您希望它全部为ints,您正在将其转换为Integer; 当double3.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-staticmember type of a raw type Rthat is not inherited from a superclass or superinterface of R.

原始类型定义为以下之一:

  • 通过采用泛型类型声明的名称而形成的引用类型,而没有随附的类型参数列表。

  • 元素类型为原始类型的数组类型。

  • 未从 的超类或超接口继承static的原始类型的非成员类型。RR

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 MyTypefor short, but technically the name is MyType<E>.

这里,MyType<E>是一个参数化类型JLS 4.5)。通常将这种类型通俗地简称MyType为简称,但从技术上讲,名称是MyType<E>.

mthas a raw type (and generates a compilation warning) by the first bullet point in the above definition; innalso has a raw type by the third bullet point.

mt上面定义中的第一个要点具有原始类型(并生成编译警告);inn第三个要点也有一个原始类型。

MyType.Nestedis 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 mt2are 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 namescontains something that isn't an instanceof String.

现在我们在运行时遇到了麻烦,因为names包含不是instanceof String.

Presumably, if you want namesto contain only String, you couldperhaps still use a raw type and manually check everyaddyourself, and then manually castto Stringevery 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 namesto 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 Listand the parameterized type List<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 a List<String>to a parameter of type List, you can't pass it to a parameter of type List<Object>. There are subtyping rules for generics, and List<String>is a subtype of the raw type List, but not of the parameterized type List<Object>. As a consequence, you lose type safety if you use raw type like List, but not if you use a parameterized type like List<Object>.

原始类型List和参数化类型之间有什么区别List<Object>?粗略地说,前者选择退出泛型类型检查,而后者明确告诉编译器它能够保存任何类型的对象。虽然可以将 a 传递List<String>给 type 的参数List,但不能将其传递给 type 的参数List<Object>。泛型有子类型规则,它List<String>是原始类型的子类型List,但不是参数化类型的子类型List<Object>。因此,如果使用类似 的原始类型ListList<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 appendNewObjectto take a raw type Listas 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 Listinstead. 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 Listdoes not have type safety, you can addjust about anything to a List.

List<Object>, List<String>, 等等都是List<?>,所以可能很想说它们只是List代替。但是,有一个主要区别:由于 aList<E>只定义了add(E),您不能将任意对象添加到 a 中List<?>。另一方面,由于原始类型List没有类型安全,您可以addList.

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-staticfield of a raw type Cthat 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 to C.

这是可能作为一种类型使用擦除参数化类型或数组类型,其元素类型是参数化类型的擦除。这种类型称为原始类型

[...]

原始类型的超类(分别为超接口)是泛型类型的任何参数化的超类(超接口)的擦除。

未从其超类或超接口继承static的原始类型的构造函数、实例方法或非字段的类型C是原始类型,该原始类型对应于对应于 的泛型声明中其类型的擦除C

In simpler terms, when a raw type is used, the constructors, instance methods and non-staticfields 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, getNamesbecomes erased as well, so that it returns a raw List!

当我们使用 raw 时MyTypegetNames也会被擦除,因此它返回一个 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 sis a signature consisting of the same name as sand the erasures of all the formal parameter types given in s.

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, not List<String>.class
  • instanceofoperand, e.g. o instanceof Set, not o 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 Collectionsand they held Objectsnothing more and nothing less. Every operation on Collectionsrequired casts from Objectto 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 CompareAbleinterface with compareTo(MyCompareAble)with raw types. Why you should not use them:

请注意,使用原始类型实现CompareAble接口是不可能的compareTo(MyCompareAble)。为什么不应该使用它们:

  • Any Objectstored in a Collectionhas 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 CompareAbleinterface, I guess that it creates two compareTofunctions, one taking a MyCompareAbleand the other taking an Objectand 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.

该警告建议定义为支持泛型的类型应该被参数化,而不是使用它们的原始形式。

Listis 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 listis a Listof 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 Integeror JFrameelements 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>()将很乐意接受IntegerJFrame元素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, Boxis 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 Boxgives you Objects. For backward compatibility, assigning a parameterized type to its raw type is allowed:

原始类型出现在遗留代码中是因为许多 API 类(例如 Collections 类)在 JDK 5.0 之前不是通用的。使用原始类型时,您基本上会获得预泛型行为 - aBox给您Objects。为了向后兼容,允许将参数化类型分配给它的原始类型:

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 @SuppressWarningssyntax, 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 个小时来解释哲学......