未经检查的 Cast 警告 - 显示类型参数但不显示具体类型?
Unchecked Cast warning - shows up for Type parameters but not for Concrete types?
考虑以下片段:
Integer a = Integer.valueOf(23);
Double d = (Double) (Number) a; //not unchecked cast
List<String> stringList = new ArrayList<>();
List<Integer> integerList = (List<Integer>)(List<?>)stringList; //unchecked cast
- 据我了解 - 每当我们转换
Supertype -> Subtype
未经检查的转换时,编译器直到运行时才知道 Supertype
表示的类型是否匹配SubType
.
- 然后在这里 - 为什么
(Double) (Number)a
没有被标记为 Unchecked Cast
?
Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the Supertype
will ever match the SubType
.
这是不正确的。甚至运行时也不知道您的列表是 ArrayList<String>
还是 ArrayList<Integer>
。就运行时而言,您的列表是 ArrayList
(这是因为 type erasure)。这就是为什么运行时无法检查将 List<?>
转换为 List<String>
的原因。运行时不知道 List<String>
是什么——它只知道 List
。对于运行时,不需要检查,因为您只是从 List
转换为 List
,这总是成功的。事实上,在运行时没有为此转换做任何事情 - 它是一个 完全未检查的 转换。
因此,这段代码运行时没有抛出异常:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.size());
它将抛出异常,但是,如果您这样做:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.get(0) - 1);
现在,您正在从列表中获取一个整数,并对它执行一些特定于整数的操作。但是列表包含 "foo"
,这不是整数。编译器插入隐式转换以将 integerList.get(0)
转换为 Integer
,但转换失败。请注意,这是经过检查的转换,因为运行时知道类型 Integer
.
还检查了从 Number
到 Double
的转换,因为运行时知道 Double
。
旁注:还有“部分未经检查的转换”,比如从 Object
转换到 ArrayList<String>
。运行时可以检查 Object
是否为 ArrayList
,但无法检查它是否为 strings.
的数组列表
查看已检查和未检查的所有规则here。
考虑以下片段:
Integer a = Integer.valueOf(23);
Double d = (Double) (Number) a; //not unchecked cast
List<String> stringList = new ArrayList<>();
List<Integer> integerList = (List<Integer>)(List<?>)stringList; //unchecked cast
- 据我了解 - 每当我们转换
Supertype -> Subtype
未经检查的转换时,编译器直到运行时才知道Supertype
表示的类型是否匹配SubType
. - 然后在这里 - 为什么
(Double) (Number)a
没有被标记为Unchecked Cast
?
Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the
Supertype
will ever match theSubType
.
这是不正确的。甚至运行时也不知道您的列表是 ArrayList<String>
还是 ArrayList<Integer>
。就运行时而言,您的列表是 ArrayList
(这是因为 type erasure)。这就是为什么运行时无法检查将 List<?>
转换为 List<String>
的原因。运行时不知道 List<String>
是什么——它只知道 List
。对于运行时,不需要检查,因为您只是从 List
转换为 List
,这总是成功的。事实上,在运行时没有为此转换做任何事情 - 它是一个 完全未检查的 转换。
因此,这段代码运行时没有抛出异常:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.size());
它将抛出异常,但是,如果您这样做:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.get(0) - 1);
现在,您正在从列表中获取一个整数,并对它执行一些特定于整数的操作。但是列表包含 "foo"
,这不是整数。编译器插入隐式转换以将 integerList.get(0)
转换为 Integer
,但转换失败。请注意,这是经过检查的转换,因为运行时知道类型 Integer
.
还检查了从 Number
到 Double
的转换,因为运行时知道 Double
。
旁注:还有“部分未经检查的转换”,比如从 Object
转换到 ArrayList<String>
。运行时可以检查 Object
是否为 ArrayList
,但无法检查它是否为 strings.
查看已检查和未检查的所有规则here。