【问题标题】:Generics List<String> and List<Integer> not behaving as expected泛型 List<String> 和 List<Integer> 未按预期运行
【发布时间】: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));

标签: java list generics arraylist


【解决方案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() 角度来看:

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

    2. 它将IntegerString 添加到ArrayList

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

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

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

    2. PrintStream类调用println(String x)

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      • 2010-09-06
      • 2022-09-30
      • 1970-01-01
      • 2012-05-29
      相关资源
      最近更新 更多