【问题标题】:What are the risks of explicitly casting from a list of type List<? extends MyObject> to a list of type List<MyObject> in Java?从 List< 类型的列表中显式转换的风险是什么?将 MyObject> 扩展为 Java 中 List<MyObject> 类型的列表?
【发布时间】:2010-08-04 07:04:14
【问题描述】:

我认为标题应该解释一切,但以防万一......

我想知道以下 Java 代码的 sn-p 会带来哪些与强制转换相关的风险和潜在问题:

List<? extends MyObject> wildcardList = someAPI.getList();
List<MyObject> typedList = (List<MyObject>) wildcardList;

我的想法是,wildcardList 中的所有对象都应该是 MyObject 的实例(确切类型或子类),因此无论何时从 typedList 中检索对象,都不应该出现 ClassCastException。它是否正确?如果是这样,为什么编译器会生成警告?

【问题讨论】:

    标签: java generics


    【解决方案1】:

    只要从列表中检索对象应该没有问题。但是如果你像下面的代码所示调用其他一些方法,它可能会导致运行时异常:

        List<Integer> intList = new ArrayList<Integer>();
        intList.add(2);
    
        List<? extends Number> numList = intList;
        List<Number> strictNumList = (List<Number>) numList;
        strictNumList.add(3.5f);
    
        int num = intList.get(1); //java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer
    

    【讨论】:

    • +1,很好的例子。然而值得指出的是,只要你只调用“get”类型的操作你甚至不需要/受益于演员表唯一 需要强制转换的时间是如果你想做一些“不安全”的事情(调用库方法的可能例外,因为它们的泛型参数不如它们应有的灵活) .
    【解决方案2】:

    关于从 typedList 中检索对象是正确的,这应该可行。

    问题是当您稍后向 typedList 添加更多对象时。例如,如果 MyObject 有两个子类 A 和 B,并且 wildcardList 的类型是 A,那么您就不能在其中添加 B。但是由于 typedList 是父类型 MyObject,所以这个错误只会在运行时被捕获。

    【讨论】:

      【解决方案3】:

      考虑你做这样的事情:

      List<ChildClassOne> childClassList = new ArrayList<ChildClassOne>();
      childClassList.add(childClassOneInstanceOne);
      childClassList.add(childClassOneInstanceTwo);
      
      List<? extends MyObject> wildcardList = childClasslist; // works fine - imagine that you get this from a method that only returns List<ChildClassOne>
      List<MyObject> typedList = (List<MyObject>) wildcardList; // warning
      
      typedList.add(childClassTwoInstanceOne); // oops my childClassList now contains a childClassTwo instance
      ChildClassOne a = childClassList.get(2); // ClassCastException - can't cast ChildClassTwo to ChildClassOne
      

      这是唯一的主要问题。但如果你只从你的列表中阅读它应该没问题。

      【讨论】:

        【解决方案4】:

        这类似于

        List<Object> obj = (List<Object>) new ArrayList<String>();
        

        我希望问题很明显。子类型列表不能转换为超类型列表。

        【讨论】:

        • 这甚至不能编译。但是 OP 正在做的事情会编译,但可能会在运行时失败。
        • 是的,没错。但我只是想证明存在根本不正确的东西。
        【解决方案5】:

        除了已经发布的答案,看看以下

        编译器会生成警告,以防该类型的元素稍后在您的代码中被访问,而该元素不是之前定义的泛型类型。运行时的类型信息也不可用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多