泛型 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<Integer>
后打印“tom”并且没有显示任何运行时异常,而转换为List<String>
后却无法打印值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
【问题讨论】:
它是显示运行时异常。 一次注释掉一种类型的列表以获得所需的输出,即 // Listprintln
的第一个调用静态分派给PrintStream.println(Object)
,第二个调用分派给PrintStream.println(String)
。因此,对于第二次调用,编译器将隐式强制转换为String
,然后在运行时以ClassCastException
失败。
【讨论】:
能否请您详细说明一下,因为我认为在第一种情况下,如果它在第二种情况下使用 PrintStream.println(String),或者两者都有 PrintStream .println(对象). 没有PrintStream.println(Integer)
。编译器总是分派给具有最具体签名的方法。 Integer
最具体的类型是Object
,String
最具体的类型是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
;
它将Integer
和String
添加到ArrayList
。
它将您的列表转换为String
列表。您的列表被标记为仅限于String
。
Java 泛型只是一个编译时特性,因此您的列表可以毫无问题地接受String
和Integer
元素。与编译器不同,对象本身对它应该包含的类型一无所知。
它尝试检索应该是 String
的已转换列表的第一个元素,并将其隐式转换为 String
。
从PrintStream
类调用println(String x)
。
但第一个元素实际上不是String
,而是Integer
。
您不能将 Integer
转换为 String
。
阅读Generics in Java 动机部分示例。
【讨论】:
以上是关于泛型 List<String> 和 List<Integer> 未按预期运行的主要内容,如果未能解决你的问题,请参考以下文章