原始类型定义为以下类型之一: 通过采用泛型类型声明的名称而不附带类型参数列表而形成的引用类型。 元素类型为原始类型的数组类型。 非- static 原始类型的成员类型 R 不是从的超类或超接口继承的 R . 下面是一个例子来说明:
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!)
}
}
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
上面的代码运行得很好,但假设您还有以下代码:
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
虽然这在大多数情况下都有效,但错误确实发生了
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
供比较:
// 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
可比较接口更复杂:
//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;}
}
3条答案
按热度按时间0ve6wy6x1#
什么是原始类型?
java语言规范定义了一个原始类型,如下所示:
jls 4.8原始类型
原始类型定义为以下类型之一:
通过采用泛型类型声明的名称而不附带类型参数列表而形成的引用类型。
元素类型为原始类型的数组类型。
非-
static
原始类型的成员类型R
不是从的超类或超接口继承的R
.下面是一个例子来说明:
在这里,
MyType<E>
是参数化类型(jls 4.5)。通俗地说,这种类型是指MyType
简而言之,但从技术上讲,这个名字是MyType<E>
.mt
按上述定义中的第一个项目符号具有原始类型(并生成编译警告);inn
第三个项目符号旁边还有一个原始类型。MyType.Nested
不是参数化类型,即使它是参数化类型的成员类型MyType<E>
,因为它是static
.mt1
,和mt2
都是用实际类型参数声明的,所以它们不是原始类型。原始类型有什么特别之处?
从本质上讲,原始类型的行为与引入泛型之前一样。也就是说,以下内容在编译时是完全合法的。
上面的代码运行得很好,但假设您还有以下代码:
现在我们在运行时遇到了麻烦,因为
names
包含的内容不是instanceof String
.想必,如果你愿意的话
names
仅包含String
,您可能仍然可以使用原始类型并手动检查add
然后手动将String
每件物品names
. 更好的是,不要使用原始类型,让编译器为您完成所有工作,利用java泛型的强大功能。当然,如果你愿意的话
names
允许Boolean
,则可以将其声明为List<Object> names
,上述代码将编译。另请参见
java教程/泛型
原始类型与使用作为类型参数有何不同?
以下是对《有效java第2版》第23条的引用:不要在新代码中使用原始类型:
原始类型之间有什么区别
List
以及参数化类型List<Object>
? 不严格地说,前者选择了泛型类型检查,而后者则明确地告诉编译器它能够保存任何类型的对象。当你能通过List<String>
类型的参数List
,不能将其传递给类型为的参数List<Object>
. 泛型有子类型规则,并且List<String>
是原始类型的子类型List
,但不是参数化类型List<Object>
. 因此,如果使用原始类型(如List
,但如果使用参数化类型(如List<Object>
.为了说明这一点,请考虑以下方法
List<Object>
并附加一个new Object()
.java中的泛型是不变的。一
List<String>
不是一个List<Object>
,因此以下内容将生成编译器警告:如果你宣布
appendNewObject
接受原始类型List
作为参数,则这将编译,因此您将失去从泛型获得的类型安全性。另请参见
两者有什么区别
<E extends Number>
以及<Number>
?java泛型(非)协方差
原始类型与使用<?>作为类型参数有何不同?
List<Object>
,List<String>
等等都是List<?>
所以说他们只是List
相反。然而,有一个主要的区别:因为List<E>
仅定义add(E)
,则不能将任意对象添加到List<?>
. 另一方面,由于原始类型List
没有类型安全,你可以add
对一个男人来说什么都可以List
.请考虑前面代码段的以下变体:
编译器在保护您避免潜在地违反
List<?>
! 如果将参数声明为原始类型List list
,则代码将编译,并且您将违反List<String> names
.原始类型是对该类型的擦除
回到jls 4.8:
可以将参数化类型的擦除或元素类型为参数化类型的数组类型的擦除用作类型。这种类型称为原始类型。
[...]
原始类型的超类(分别是超接口)是泛型类型的任何参数化的超类(超接口)的擦除。
构造函数、示例方法或非构造函数的类型-
static
原始类型的字段C
不是从其超类或超接口继承的是原始类型,它对应于C
.简单地说,当使用原始类型时,构造函数、示例方法和非-
static
字段也会被删除。举下面的例子:
当我们使用生的
MyType
,getNames
也会被擦除,因此它返回一个原始值List
!jls 4.6继续解释以下内容:
类型擦除还将构造函数或方法的签名Map到没有参数化类型或类型变量的签名。删除构造函数或方法签名
s
是由与相同的名称组成的签名s
以及中给出的所有形式参数类型的删除s
.如果方法或构造函数的签名被删除,则方法的返回类型和泛型方法或构造函数的类型参数也会被删除。
泛型方法签名的擦除没有类型参数。
以下错误报告包含编译器开发人员maurizio cimadamore和jls作者之一alex buckley关于为什么应该发生这种行为的一些想法:https://bugs.openjdk.java.net/browse/jdk-6400189. (简而言之,它使规范更简单。)
如果不安全,为什么允许使用原始类型?
以下是jls 4.8的另一句话:
只允许使用原始类型作为对遗留代码兼容性的让步。强烈反对在java编程语言中引入泛型之后编写的代码中使用原始类型。java编程语言的未来版本可能会禁止使用原始类型。
有效的java第2版还需要添加以下内容:
既然你不应该使用原始类型,为什么语言设计者允许它们呢?提供兼容性。
当泛型被引入时,java平台即将进入第二个十年,并且存在大量不使用泛型的java代码。所有这些代码都必须合法,并且可以与使用泛型的新代码进行互操作。将参数化类型的示例传递给设计用于普通类型的方法必须是合法的,反之亦然。这个被称为迁移兼容性的需求推动了支持原始类型的决定。
总之,新代码中不应使用原始类型。应该始终使用参数化类型。
没有例外吗?
不幸的是,由于java泛型是非具体化的,所以在新代码中必须使用原始类型时有两个例外:
类文字,例如。
List.class
,不是List.class
instanceof
操作数,例如。o instanceof Set
,不是o instanceof Set<String>
####另请参见为什么是
Collection<String>.class
非法的?eoigrqb62#
原始类型是没有任何类型参数的泛型类或接口的名称。例如,给定泛型box类:
创建参数化类型
Box<T>
,则为形式类型参数提供实际的类型参数T
:如果省略了实际的类型参数,则创建
Box<T>
:因此,
Box
泛型类型的原始类型Box<T>
. 但是,非泛型类或接口类型不是原始类型。原始类型出现在遗留代码中,因为在JDK5.0之前,许多api类(如collections类)不是泛型的。当使用原始类型时,基本上可以得到预泛型
9rbhqvlz3#
java中的原始类型是什么?为什么我经常听说不应该在新代码中使用它们?
原始类型是java语言的古老历史。起初有
Collections
他们坚持住了Objects
不多也不少。上的每个操作Collections
所需的强制转换自Object
到所需类型。虽然这在大多数情况下都有效,但错误确实发生了
旧的无类型集合不能强制执行类型安全,因此程序员必须记住他在集合中存储的内容。
泛型是为了绕过这个限制而发明的,开发人员只需声明一次存储的类型,编译器就可以这样做。
供比较:
可比较接口更复杂:
请注意,不可能实现
CompareAble
接口compareTo(MyCompareAble)
原始类型。为什么不应该使用它们:任何
Object
储存在Collection
必须先浇铸才能使用使用泛型可以进行编译时检查
使用原始类型与将每个值存储为
Object
编译器的作用:泛型是向后兼容的,它们使用与原始类型相同的java类。这种魔力主要发生在编译时。将编译为:
这与直接使用原始类型时编写的代码相同。我想我不知道这件事会发生什么
CompareAble
接口,我猜它创建了两个compareTo
函数,一个取一个MyCompareAble
另一个拿着枪Object
把它扔给第一个。原始类型的替代方法是什么:使用泛型