问题:

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


当前回答

教程页面。

原始类型是没有任何类型参数的泛型类或接口的名称。例如,给定泛型Box类:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

要创建Box的参数化类型,请为正式类型参数T提供一个实际的类型参数:

Box<Integer> intBox = new Box<>();

如果省略了实际类型参数,则创建原始类型Box:

Box rawBox = new Box();

其他回答

原始类型是没有任何类型参数的泛型类或接口的名称。例如,给定泛型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教程

我在做了一些示例练习后发现了这一页,并有着完全相同的困惑。

===============我根据示例提供的代码===============

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());
    }

=========================到此代码========================

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());
    }

}

===============================================================================

这可能更安全,但花了4个小时来驳斥哲学。。。

当原始类型表达您想要表达的内容时,它们是很好的。

例如,取消序列化函数可能返回List,但它不知道列表的元素类型。所以List是这里合适的返回类型。

简单综合一下:原始类型是一个没有类型参数的泛型类型(例如: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;
}

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

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

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