【问题标题】:For statement over a list of unknown type casting对于未知类型转换列表的声明
【发布时间】:2018-10-01 07:25:21
【问题描述】:

我正在尝试在 for 循环中自动将对象列表的每个元素转换为正确的类型

class A {

}

class B {
  void sampleMethod() {
    List<?> l1 = //initialized somewhere;
    /* 
       I do know perfectly l1 got elements of Class A
       I just could not declare List<A> for other (generic types) reasons
    */
    for (A el: l1) { // Type mismatch: cannot convert from element type capture#1-of ? to A
      System.out.println(el);
    }
  }
}

正如我在代码中发布的那样,“for 语句”显示错误:

类型不匹配:无法从元素类型 capture#1-of 转换?到A

我尝试过其他解决方案,例如:

for (A el: (List<A>)l1)

这会导致警告:

类型安全:从 List 到 List 的未经检查的强制转换

最后我找到了一个可行的(但在我看来并不合适)的解决方案,即在 for: 中进行转换:

for (Object el: l1) {
    A listEl = (A) el;
    System.out.println(el);
}

为什么我不能在 for 语句中进行这种类型的转换?真的没有办法干净利落吗?

【问题讨论】:

  • List&lt;? extends A&gt; 工作吗?
  • 你不能使用List&lt;Object&gt;有什么原因吗?
  • @ShanuGupta 效果很好!对我来说很有意义!谢谢!!

标签: java generics casting


【解决方案1】:

真的没有办法干净利落吗?

如果您使用通配符声明List

List<?> l1 = //initialized somewhere;

您永远无法在没有任何警告的情况下将其元素转换为特定类型。
您尝试做的事情违背了泛型的目的。

您在评论中写道:

由于其他(通用类型)原因,我无法声明 List&lt;A&gt;

没有通配符或绑定的通用变量(例如List&lt;A&gt;)有一些限制。众所周知,您不能为其分配List&lt;B&gt;,其中BA 的子类。但是还有其他方法可以让它作为List&lt;? extends A&gt; 工作,同时它也有一些其他的限制。

事实上,您在声明List&lt;A&gt; 时并没有描述遇到的问题。所以很难提供一个具体的解决方案。
但我认为,如果您只操作列表中的 A 实例,则应该遵循声明更具体的类型。
因此,如果List&lt;A&gt; 导致您的代码出现问题,请深入研究这个问题,如果“无法解决”,为什么不问这个问题。

【讨论】:

    【解决方案2】:

    如果以下情况成立,“我完全知道 l1 得到了 A 类的元素”,那么试试:

    List<?> l1 = ...
    
    @SuppressWarnings("unchecked")
    List<A> l2 = (List<A>) l1;
    
    for (A a: l2) { ... }
    

    但更简洁的方法是遍历原始列表,检查元素的类型,然后在没有警告的情况下进行转换:

    for (Object generic: l1) {
        if (generic instanceof A) {
            A a = (A) generic; // without warnings
            // do stuff
        } else if (generic == null) { // if nulls possible
            // do stuff
        } else {
            throw new IllegalArgumentException("item not of class A");
        }
    }
    

    【讨论】:

      【解决方案3】:

      您在循环内使用强制转换元素的解决方案是完全合适的。 List&lt;?&gt; 是一个未知列表,一个元素类型匹配任何东西的集合。因此,您唯一可以确定的是所有项目都是对象,所以您可以这样做。这总是安全的,因为无论集合的实际类型是什么,它都包含对象。您可以参考Oracle Generics tutorial 中的类似案例,这被认为是很好的代码示例。

      希望对你有帮助!

      【讨论】:

        猜你喜欢
        • 2016-01-19
        • 1970-01-01
        • 1970-01-01
        • 2010-12-09
        • 2011-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多