Java通配符:强制转换的最佳实践

9

我进行了广泛的研究,似乎找不到这种情况的最佳实践。

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语句明确检查了类型,因此我并不担心异常,但是有没有更好的方法在不必抑制未经检查的警告的情况下完成这个操作呢?在这种情况下有最佳实践吗? 我已经阅读了完整的Generics Oracle教程 here ,也阅读了许多stackoverflow帖子,但似乎没有一个能够解决这个问题。任何帮助都将不胜感激。谢谢。

1
非常牵强的例子?如果您仍然添加通配符实例,那么泛型包装器的意义何在?顺便说一下,对象包含Integer并不意味着它必须是GenericObject<Integer>,它也可以是GenericObject<Number>(因此允许某些方法用Double替换“装箱”的Integer)。 - mihi
最好的解决方法可能是让 GenericObject<T> 接受另一个 Class<T> 作为参数并存储它,然后有一个静态辅助转换方法(抑制未检查的警告),该方法接受 GenericObject<?>Class<T> 并在验证存储的 Class<T> 值后将其转换为 GenericObject<T> - mihi
谢谢@mihi。我明白你的观点,关于将类定义为数字类型并让某人传递整数。这是一个很好的观点,我没有想到过。至于这个例子的重点。假设我有一个包含所有类型数据的数据表。我想把它放在表格中,所以我创建了一个名为Column<T>的对象;Column也有一个类型为T的ArrayList。如果我把所有这些列都放在一个ArrayList中,我会得到ArrayList<Column<?>>;现在我需要添加一行新数据。我必须将所有列强制转换为它们的原始类型,以便向它们的内部数组添加值。 - rickmaster
对于具有恒定列类型(和恒定列数)的表,我会尝试将它们建模为行列表(每个行都是一个自定义类型,具有正确类型的字段),而不是列列表。这样,您的列就有名称和类型,并且添加新行很容易 :) - mihi
确实,那将是实现它的方式。我正在构建的是一个框架,用于从数据库和可能的Excel电子表格中创建表格表示,其中表格行是不可预测的。 - rickmaster
2个回答

5

不,没有比抑制警告更好的方法,但需要提供解释:

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

请注意,这并不一定是一个好的设计 - 最好避免未经检查的转换,如果可能的话,仅仅因为它们很难被证明是正确的。例如,如果gi之前被声明为GenericObject<Object>GenericObject<Number>,然后恰好保存了一个Integer,那该怎么办呢?最好检查和转换值本身:
GenericObject<?> go = list.get(0);
Object obj = go.getGenericValue();
if (obj instanceof Integer) { // or obj.getClass() == Integer.class
     System.out.println("Was Integer");
}

是的,我认为在这种情况下第二个选项是最好的选择。 - Giovanni Botta
感谢您的回答。然而,最终目标是能够使用键入的泛型,并且例如添加另一个相同类型的值。即 gi.setValue2(8); 其中该方法定义为 "public void setGenaricValue2( T genaricValue )." - rickmaster

0

我认为没有办法在不出现警告的情况下完成这个操作。 GenericObject<T> 的类型参数 T 总是在运行时被擦除,因此即使您使用了 instanceof 运算符(在其他情况下可以消除警告),您也无法将其用于泛型类,例如,if(o instanceof GenericObject<Integer>) 将无法编译。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接