为什么可以从Java中的参数化列表中取回“不正确类型”的对象?

下面是一个代码片段:

import java.util.*;
class Test
{
    public static void main(String[] args)
    {
        List<Integer> list = new ArrayList<>();
        addToList(list);
        Integer i = list.get(0); //#1 fails at run-time
        String s = list.get(0); //#2 fails at compile-time
        list.get(0); //#3 works fine
        System.out.println(list.get(0)); //#4 works fine, prints "string"
    }
    static void addToList(List list){
        list.add("string");
    }
}

我理解为什么可以在参数化列表中插入 String 类的对象。

似乎我理解为什么代码标记为和失败。#1#2

但是,为什么要这样做和工作呢?据我所知,编译器在类型擦除后添加了适当的强制转换,因此当我调用时,此方法应返回先前强制转换为整数的对象。那么,为什么在运行时#3和#4没有ClassCastException发生呢?#3#4list.get(0)


答案 1

#3 之所以有效,是因为 返回的对象被忽略。存储在位置的任何内容都会返回,但由于没有强制转换,因此不会发生错误。get(int)0

出于同样的原因,#4 工作正常:生成的对象被视为 中的子类,因为被调用。由于 它可用于所有 Java 对象,因此调用完成时不会出现错误。get(0)java.lang.ObjectprintlntoStringtoString()


答案 2

首先,您可以向 .在方法中List<Integer>

static void addToList(List list){

您使用原始类型。原始类型的存在纯粹是为了与较旧的 Java 版本兼容,不应在新代码中使用。在该方法中,Java 编译器不知道它应该只包含整数,因此当向其中添加字符串时,它不会抱怨。addToListlist

至于你们两个语句的不同行为。 在编译时不会失败,因为 Java 认为 它只包含 s。只有在运行时,它才证明 的第一个元素不是整数,因此您得到一个 .Integer i = list.get(0)listIntegerlistClassCastException

String s = list.get(0)在编译时失败,因为 Java 编译器假定它只包含整数,因此它假定您尝试将整数分配给字符串引用。list

只是不存储方法调用的结果。因此,无论是在编译时还是在运行时,都没有任何失败的原因。list.get(0)

最后,工作因为是一个,并且有一个方法,可以用参数调用。System.out.println(list.get(0))System.outPrintStreamprintln(Object)Integer


推荐