【问题标题】:Java wild card BestPractices for casting用于强制转换的 Java 通配符最佳实践
【发布时间】:2014-01-20 17:26:35
【问题描述】:

我对此进行了广泛的研究,但似乎无法找到适合这种情况的最佳做法。

ArrayList<GenericObject<?>> list = new ArrayList<>();
list.add( new GenericObject<Integer>(6) ); // Autoboxing
list.add( new GenericObject<String>("HI") );
if(list.get( 0 ).getGenaricValue().getClass() == Integer.class){

        GenericObject<Integer> gi = (GenericObject<Integer>) list.get( 0 );
        System.out.println("Was Integer");
        System.out.println(gi);
    }
}

当这段代码工作时,从 GenericObject > 到 GenericObject 的转换会给出未经检查的警告。现在你可以看到我已经用我的 if 语句清楚地检查了类型,所以我对异常并不偏执,但是有没有更好的方法来做到这一点而不必抑制未经检查的警告?这种情况有最佳实践吗? 我已经阅读了整个泛型 oracle 教程 here 并且我已经阅读了很多 stackoverflow 帖子,但似乎没有一个可以回答这个问题。任何帮助将不胜感激。

【问题讨论】:

  • 非常人为的例子?如果无论如何添加通配符实例,通用包装器的意义何在?顺便说一句,对象包含Integer 的事实并不意味着它必须是GenericObject&lt;Integer&gt;,它也可能是GenericObject&lt;Number&gt;(因此允许某些方法将“盒装”Integer 替换为Double.)
  • 解决这个问题的最佳方法可能是让GenericObject&lt;T&gt; 将另一个Class&lt;T&gt; 作为参数并存储它,并有一个静态辅助转换方法(抑制未经检查的警告),它采用@ 987654330@ 和 Class&lt;T&gt; 并在验证存储的 Class&lt;T&gt; 值后将其转换为 GenericObject&lt;T&gt;
  • 谢谢@mihi。我看到你关于类被定义为类型号并让一些人传入一个整数的观点。这是一个很好的观点,我没有想到这一点。至于这个例子的意义。假设我有一个所有类型的数据表。我想把它放在表格中,所以我创建了一个名为 Column; 的对象。 Column 也有一个 T 类型的 ArrayList。如果我将所有这些列放在一个 ArrayList 中,我将拥有 ArrayList>;现在我需要添加一个新行。我必须将所有列转换为它们的原始类型才能将值添加到它们的内部数组
  • 对于具有恒定列类型(和恒定列数)的表,我会尝试将它们建模为行列表(每个行都是具有正确类型字段的自定义类型行),而不是列列表。这样一来,您的列就有了名称和类型,并且添加新行很容易 :)
  • 确实是这样。我正在构建的更多的是一个框架,用于从数据库创建表格表示形式,也许还有 Excel 电子表格,其中表格行是不可预测的。

标签: java generics casting wildcard


【解决方案1】:

不,没有比取消警告更好的方法了,并附上解释:

@SuppressWarnings("unchecked") // this is okay because [insert reasoning]
GenericObject<Integer> gi = (GenericObject<Integer>) list.get( 0 );

但请注意,这不一定是一个好的设计 - 如果可能,最好避免未经检查的强制转换,因为它们很难证明是正确的。例如,如果 gi 早先被输入为 GenericObject&lt;Object&gt;GenericObject&lt;Number&gt; 并且恰好包含 Integer 怎么办?检查并转换值本身可能会更好:

GenericObject<?> go = list.get(0);
Object obj = go.getGenericValue();
if (obj instanceof Integer) { // or obj.getClass() == Integer.class
     System.out.println("Was Integer");
}

【讨论】:

  • 是的,我认为第二个是这种情况下的最佳选择。
  • 感谢您的回答。不过,这里的最终目标是能够使用类型化的泛型,例如,添加另一个相同类型的值。即 gi.setValue2(8);其中方法定义为“public void setGenaricValue2(T genaricValue)”。
【解决方案2】:

我认为没有警告就没有办法做到这一点。 GenericObject&lt;T&gt; 的类型参数 T 总是在运行时被删除,所以即使你使用了 instanceof 运算符(在其他情况下会消除警告),你也不能在泛型类上使用它,例如, if(o instanceof GenericObject&lt;Integer&gt;) 不会编译。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    相关资源
    最近更新 更多