泛型 List<String> 和 List<Integer> 未按预期运行

Posted

技术标签:

【中文标题】泛型 List<String> 和 List<Integer> 未按预期运行【英文标题】:Generics List<String> and List<Integer> not behaving as expected 【发布时间】:2014-12-02 17:54:00 【问题描述】:

为什么println 转换为List&lt;Integer&gt; 后打印“tom”并且没有显示任何运行时异常,而转换为List&lt;String&gt; 后却无法打印值1?

import java.util.Arrays;
import java.util.List;

public class Main 
    public static void main(String args[]) 

        List list = Arrays.asList(1, "tom");

        System.out.println(((List<Integer>) list).get(1));
        // "tom"

        System.out.println(((List<String>) list).get(0));
        // ClassCastException: Integer cannot be cast to String
    

【问题讨论】:

显示运行时异常。 一次注释掉一种类型的列表以获得所需的输出,即 // List list3 = list1; // System.out.println(list3.get(0)); 【参考方案1】:

println 的第一个调用静态分派给PrintStream.println(Object),第二个调用分派给PrintStream.println(String)。因此,对于第二次调用,编译器将隐式强制转换为String,然后在运行时以ClassCastException 失败。

【讨论】:

能否请您详细说明一下,因为我认为在第一种情况下,如果它在第二种情况下使用 PrintStream.println(String),或者两者都有 PrintStream .println(对象). 没有PrintStream.println(Integer)。编译器总是分派给具有最具体签名的方法。 Integer 最具体的类型是ObjectString 最具体的类型是String 感谢您的快速解释。【参考方案2】:

这里的问题是 java 编译器在编译时选择方法,而不是运行时。 并且在编译时它会选择方法PrintStream.print(String),而不是PrintStream.print(int)PrintStream.print(Object),两者都会成功。

【讨论】:

【参考方案3】:
Integer i = new Integer(101);
String s = new String(i); // undefined and Invalid
StringBuffer sb = new StringBuffer(i); // defined and Valid

String s2 = "tom";
Integer i2 = new Integer(s2); //defined and valid

因此,当您将非泛型列表分配给泛型列表时,它会被分配,但是当您打印它时,它会检查类型安全性或定义构造函数以进行转换,如果存在有效且已定义的构造函数,则打印它,否则会显示类转换异常由于缺少用于转换的未定义构造函数,因此无法转换该类。

如果我错了,请帮助我正确的逻辑......

【讨论】:

这与构造函数无关。【参考方案4】:

使用泛型可以避免此类问题,这是使用泛型的主要动机。

这是您的代码的实际流程,从您的第二个println() 角度来看:

    您的代码声明了 ArrayList 类型的 Object

    它将IntegerString 添加到ArrayList

    它将您的列表转换为String 列表。您的列表被标记为仅限于String

Java 泛型只是一个编译时特性,因此您的列表可以毫无问题地接受StringInteger 元素。与编译器不同,对象本身对它应该包含的类型一无所知。

    它尝试检索应该是 String 的已转换列表的第一个元素,并将其隐式转换为 String

    PrintStream类调用println(String x)

但第一个元素实际上不是String,而是Integer。 您不能将 Integer 转换为 String

阅读Generics in Java 动机部分示例。

【讨论】:

以上是关于泛型 List<String> 和 List<Integer> 未按预期运行的主要内容,如果未能解决你的问题,请参考以下文章

泛型、类型参数和通配符

泛型 List<String> 和 List<Integer> 未按预期运行

list的泛型

扩展方法泛型委托,的小案例

Java里的泛型加通配符的用法

字符串 “Map<String,List<String>>”如何获取到它的泛型的Type