问题:

Java中的原始类型是什么?为什么我经常听到不应该在新代码中使用它们?如果我们不能使用原始类型,还有什么替代方法?如何更好?


当前回答

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中的“原始”类型是一个非泛型类,它处理“原始”对象,而不是类型安全的泛型类型参数。

例如,在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一起使用。这一事实是泛型的主要驱动因素。它将运行时错误源更改为可在编译时检查的内容。

在这里,我考虑了多个案例,通过这些案例,你可以明确概念

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是一种原始类型。

警告:-严格类型对象引用到原始类型引用的变量。

 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,但它不知道列表的元素类型。所以List是这里合适的返回类型。