有没有办法在此代码中避免@SuppressWarnings?

时间:2010-09-16 19:25:47

标签: java arrays generics collections casting

有没有办法避免使用下面的@SuppressWarnings并保持相同的功能而没有警告'类型安全:从AbstractDO []取消选中投射到E []'

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);
  }
  ...
}

也许增强地图声明?

3 个答案:

答案 0 :(得分:3)

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

只有这两个选择。

  

也许有一种方法可以增强地图声明?

在你的情况下,我会说你有几个选择。

我认为您最好的选择是在throws ClassCastException方法中添加getConcreteDOs子句,并让调用者处理无效使用该方法所带来的无效演员 - 假设他们可以获得它围绕你的extends AbstractDO条款进行编译。这会产生令人遗憾的副作用,即强制消费者将调用包装在try / catch块中,或者声明自己的throws子句以强制try / catch块在堆栈上方。

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

或者您可以完全删除该方法,只处理抽象实体,有效地使您的存储库的使用者处理转换。

结论:每当您尝试构建通用存储库时,您都会遇到这些问题。使用具体的每个实体类型的存储库模式可能会更好。

答案 1 :(得分: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);
    }
}

答案 2 :(得分: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()为我们隐藏警告,就是这样。

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

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

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