2010-09-16 119 views
3

有没有办法避免以下使用@SuppressWarnings,并保持相同的功能,而不警告“类型安全:未选中从AbstractDO []转换为E []”有没有办法在此代码中避免@SuppressWarnings?

public MyClass { 
    ... 
    private Map<Class<? extends AbstractDO>, AbstractDO[]> map; 
    ... 
    private void saveConcreteDOs(AbstractDO[] theEntities) {   
    entityMap.put(theEntities[0].getClass(), theEntities); 
    } 

    @SuppressWarnings("unchecked") 
    protected <E extends AbstractDO> E[] getConcreteDOs(Class<E> theType) { 
    return (E[]) map.get(theType); 
    } 
    ... 
} 

也许提高地图的声明?

+0

以防万一,请忽略NPE和类似的错误 - 代码缩短版,当然 – topchef 2010-09-16 19:27:58

+5

数组和仿制药不拌匀,更好地利用列表,而不是。 – starblue 2010-09-16 19:37:15

+0

谢谢,这是一个选项。 – topchef 2010-09-16 19:42:15

回答

3

您可以选择:抑制您知道总是会成功的演员的警告,或者避免警告并验证演员是否通过了try/catch块。

只有这两种选择。

maybe there is a way to enhance map declaration?

就你而言,我会说你有几个选择。

我认为最好的办法是到throws ClassCastException条款添加到您的getConcreteDOs方法,让来电处理无效的投带来的无效使用的方法 - 假设他们可以得到它来编译在你extends AbstractDO条款。这具有强制消费者在try/catch块中包装调用或者声明他们自己的throws子句以强制try/catch块在堆栈上更高的不利副作用。

你可以用一个空的catch块吞下异常;坦率地说,我更喜欢@SuppressWarning。

或者您可以完全放弃该方法,只处理抽象实体,从而有效地使存储库的使用者处理演员阵容。底线:每当您尝试构建通用存储库时,都会遇到这些问题。使用每个实体类型的具体存储库模式可能会更好。

+0

也许有一种方法来增强地图声明? – topchef 2010-09-16 19:35:53

+1

打败我吧;我想说,无论何时,当你从父母转到孩子时,你总是会得到这个警告,因为编译器没有办法保证这些类型是兼容的。 – 2010-09-16 19:44:43

+0

你的意思是“@SuppressWarnings”注释会影响运行时行为? (不管是否投射成功)我是否正确理解你?现在,这是一个消息。 – 2010-09-16 19:51:10

1

你可以通过让你的类变为一般的方法来避免未经检查的转换。

public class MyClass<E extends AbstractDO> { 

    private Map<Class<? extends AbstractDO>, E[]> map; 

    public void saveConcreteDOs(E[] theEntities) {   
     map.put(theEntities[0].getClass(), theEntities); 
    } 

    public E[] getConcreteDOs(Class<E> theType) { 
     return map.get(theType); 
    } 
} 
+1

我认为当我用X.class作为参数调用X []时,其意图是返回一个X [],因此该映射将包含每个类和相应数组的一个条目。你的建议意味着强制所有的数组子类E ... – helios 2010-09-16 20:20:11

+0

没错,helios。 – topchef 2010-09-16 20:30:01

+0

@grigory,那么如果没有未经检查的演员,你将无法脱身。 – 2010-09-16 20:34:50

1

首先,您的代码不是类型安全的。它可以在运行时抛出类转换异常。您应该有

 
    private void saveConcreteDOs(AbstractDO[] theEntities) {   
    entityMap.put(theEntities.getClass().getComponentType(), theEntities); 
    } 

您可能在运行时只有同类数组,并且元素[0]与数组元素类型的类型相同。然而,单靠考察这门课是无法知道的。

有了这个更正的代码,超级智能编译器可以证明getConcreteDOs()是类型安全的。但是,javac并不那么聪明。语言规范要求提供警告。

通常,在Java中,无法表示键和值之间更复杂的关系。不变量,一个值是一个数组,其组件类型是关键字,只保留在你的头上。

现在,看看这个非数组版本:

private Map<Class<? extends AbstractDO>, AbstractDO> map; 

protected <E extends AbstractDO> E getConcreteDOs(Class<E> theType) 
{ 
    AbstractDO obj = map.get(theType); 
    return theType.cast(obj); 
} 

这有没有报警,但它的那种作弊。 Class.cast()隐藏了我们的警告,就这些。

它没有帮助阵列版本,Class<T>中没有T[] castArray(Object[])。你可以自己制作一种方法,有效地隐藏它的警告。

或者你可以做到这一点,但它确实是不必要的俗气。如果您知道自己在做什么,并且您仔细检查了程序以确保类型安全,请不要担心未经检查的警告。

protected <E extends AbstractDO> E[] getConcreteDOs(Class<E[]> arrayType) 
{ 
    AbstractDO[] array = map.get(arrayType.getComponentType()); 
    return arrayType.cast(array); 
} 
... 
X[] array = getConcreteDOs(X[].class); 
+0

我同意避免警告和“@SupressWarnings”本身不是目标。目标是要有清晰,充分和自我解释的代码。这就是为什么我喜欢你的'如果你知道你在做什么,并且你仔细检查了你的程序以确保类型的安全,不要害怕不加控制的警告。 – topchef 2010-09-17 04:25:41

+0

关于类型安全的第一个注意事项对我而言并不清楚。 'TheEntities [0] .getClass()'可能不会转换为'Class <?扩展AbstractDO>'? – topchef 2010-09-17 04:28:59

+0

@grigory说B是A的子类,如果'array = new A [] {new B(),new A()}',你的代码会认为该数组是'B []' – irreputable 2010-09-17 14:46:06

相关问题