问题:
Java中的原始类型是什么?为什么我经常听到不应该在新代码中使用它们?如果我们不能使用原始类型,还有什么替代方法?如何更好?
问题:
Java中的原始类型是什么?为什么我经常听到不应该在新代码中使用它们?如果我们不能使用原始类型,还有什么替代方法?如何更好?
当前回答
意思是你的列表是一个未指定对象的列表。也就是说,Java不知道列表中有什么类型的对象。然后,当您想要迭代列表时,必须强制转换每个元素,以便能够访问该元素的财产(在本例中为String)。
一般来说,将集合参数化是一个更好的主意,因此您不会遇到转换问题,您只能添加参数化类型的元素,编辑器将为您提供合适的选择方法。
private static List<String> list = new ArrayList<String>();
其他回答
private static List<String> list = new ArrayList<String>();
您应该指定类型参数。
警告建议,应将定义为支持泛型的类型参数化,而不是使用其原始形式。
List被定义为支持泛型:公共类List<E>。这允许在编译时检查许多类型安全操作。
原始类型是没有任何类型参数的泛型类或接口的名称。例如,给定泛型Box类:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
要创建Box<T>的参数化类型,请为正式类型参数T提供一个实际的类型参数:
Box<Integer> intBox = new Box<>();
如果省略了实际类型参数,则创建Box<T>的原始类型:
Box rawBox = new Box();
因此,Box是泛型类型Box<T>的原始类型。但是,非泛型类或接口类型不是原始类型。
原始类型出现在遗留代码中,因为许多API类(如Collections类)在JDK5.0之前不是通用的。当使用原始类型时,基本上会得到预泛型行为——一个Box会给你对象。为了向后兼容,允许将参数化类型分配给其原始类型:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
但如果将原始类型分配给参数化类型,则会收到警告:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
如果使用原始类型调用相应泛型类型中定义的泛型方法,也会收到警告:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
警告显示,原始类型绕过泛型类型检查,将不安全代码的捕获延迟到运行时。因此,应避免使用原始类型。
类型擦除部分提供了有关Java编译器如何使用原始类型的更多信息。
未选中的错误消息
如前所述,当混合传统代码和通用代码时,您可能会遇到类似于以下内容的警告消息:
注意:Example.java使用未检查或不安全的操作。注意:使用-Xlint:未选中以获取详细信息。
当使用对原始类型进行操作的旧API时,可能会发生这种情况,如下例所示:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
术语“未检查”意味着编译器没有足够的类型信息来执行确保类型安全所需的所有类型检查。默认情况下,“未检查”警告被禁用,尽管编译器会给出提示。要查看所有“未检查”警告,请使用-Xlint:unchecked重新编译。
使用-Xlint:unchecked重新编译上一个示例将显示以下附加信息:
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
要完全禁用未检查的警告,请使用-Xlint:未检查标志。@SuppressWarnings(“unchecked”)注释可抑制未选中的警告。如果您不熟悉@SuppressWarnings语法,请参阅注释。
原始来源:Java教程
避免使用原始类型。
原始类型是指在不指定类型参数的情况下使用泛型类型。
例如:
列表是原始类型,而list<String>是参数化类型。
当JDK1.5中引入泛型时,原始类型仅被保留以保持与旧版本Java的向后兼容性。
尽管仍然可以使用原始类型,但应避免使用:
他们通常需要石膏。它们不是类型安全的,一些重要类型的错误只会在运行时出现。它们的表达力较低,并且不像参数化类型那样自我文档化。。
例子:
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));
}
}
供参考:https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
编译器希望您编写以下内容:
private static List<String> list = new ArrayList<String>();
因为否则,您可以将任何您喜欢的类型添加到列表中,使实例化为新的ArrayList<String>()变得毫无意义。Java泛型只是一个编译时特性,因此,如果将新的ArrayList<String>()创建的对象分配给“原始类型”List的引用,它将欣然接受Integer或JFrame元素-对象本身不知道应该包含什么类型,只有编译器知道。
简单综合一下:原始类型是一个没有类型参数的泛型类型(例如:List是List<E>的原始类型),不应该使用原始类型。它们的存在是为了与旧版本的Java兼容。我们希望尽快(编译时)发现错误,使用原始类型可能会在运行时导致错误。在两种情况下,我们仍然需要使用原始类型:
类文字的用法(List.class)instanceof的用法
示例:
//Use of raw type : don't !
private final Collection stamps = ...
stamps.add(new Coin(...)); //Erroneous insertion. Does not throw any error
Stamp s = (Stamp) stamps.get(i); // Throws ClassCastException when getting the Coin
//Common usage of instance of
if (o instanceof Set){
Set<?> = (Set<?>) o;
}