问题:
Java中的原始类型是什么?为什么我经常听到不应该在新代码中使用它们?如果我们不能使用原始类型,还有什么替代方法?如何更好?
问题:
Java中的原始类型是什么?为什么我经常听到不应该在新代码中使用它们?如果我们不能使用原始类型,还有什么替代方法?如何更好?
当前回答
原始类型是在使用泛型类型时缺少类型参数。
不应使用原始类型,因为它可能会导致运行时错误,例如将双精度值插入到一组int中。
Set set = new HashSet();
set.add(3.45); //ok
当从集合中检索内容时,你不知道会发生什么。让我们假设您希望它是所有整数,您将其转换为整数;当出现双3.45时,运行时出现异常。
将类型参数添加到Set后,您将立即收到编译错误。这种抢先错误允许您在运行时发生问题之前修复问题(从而节省时间和精力)。
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
其他回答
Java中的“原始”类型是一个非泛型类,它处理“原始”对象,而不是类型安全的泛型类型参数。
例如,在Java泛型可用之前,您可以使用这样的集合类:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
当您将对象添加到列表中时,它并不关心它是什么类型的对象,当您从列表中获取它时,您必须将其显式转换为您期望的类型。
使用泛型,可以删除“未知”因素,因为必须明确指定列表中可以包含的对象类型:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
注意,对于泛型,您不必强制转换来自get调用的对象,集合是预定义的,只能与MyObject一起使用。这一事实是泛型的主要驱动因素。它将运行时错误源更改为可在编译时检查的内容。
意思是你的列表是一个未指定对象的列表。也就是说,Java不知道列表中有什么类型的对象。然后,当您想要迭代列表时,必须强制转换每个元素,以便能够访问该元素的财产(在本例中为String)。
一般来说,将集合参数化是一个更好的主意,因此您不会遇到转换问题,您只能添加参数化类型的元素,编辑器将为您提供合适的选择方法。
private static List<String> list = new ArrayList<String>();
教程页面。
原始类型是没有任何类型参数的泛型类或接口的名称。例如,给定泛型Box类:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
要创建Box的参数化类型,请为正式类型参数T提供一个实际的类型参数:
Box<Integer> intBox = new Box<>();
如果省略了实际类型参数,则创建原始类型Box:
Box rawBox = new Box();
在这里,我考虑了多个案例,通过这些案例,你可以明确概念
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
案例1
ArrayList<String>arr它是一个类型为String的ArrayList引用变量,它引用的是一个字符串类型的ArralyList对象。这意味着它只能保存String类型的Object。
它是一个Strict to String,而不是Raw类型,因此它不会引发警告。
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)
案例2
在这种情况下,ArrayList<String>arr是一个严格类型,但您的Object new ArrayList();是原始类型。
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)
这里arr是严格类型。所以,当添加整数时,它会引发编译时错误。
警告:-原始类型对象引用到ArrayList的严格类型引用变量。
案例3
在本例中,ArrayList arr是一个原始类型,但Object new ArrayList<String>();是严格类型。
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
它将向其中添加任何类型的对象,因为arr是一种原始类型。
警告:-严格类型对象引用到原始类型引用的变量。
这是另一种生肉会咬你的情况:
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();
}
}
这是反直觉的,因为您希望原始类型只影响绑定到类类型参数的方法,但实际上它也影响具有自己类型参数的泛型方法。
正如在公认的答案中所提到的,您将失去对原始类型代码中泛型的所有支持。每个类型参数都转换为其擦除(在上面的示例中,它只是Object)。