Есть ли способ избежать @SuppressWarnings в этом коде? - PullRequest
3 голосов
/ 16 сентября 2010

Есть ли способ избежать использования @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 ]

3 голосов
/ 16 сентября 2010

У вас есть выбор: либо подавить предупреждение для броска, который, как вы знаете, всегда будет успешным, либо избежать предупреждения и убедиться, что приведение прошло успешно с помощью блока try / catch.

Есть только эти два варианта.

может быть, есть способ улучшить объявление карты?

В вашем случае, я бы сказал, у вас есть несколько вариантов.

Я думаю, что вам лучше всего добавить пункт throws ClassCastException в ваш метод getConcreteDOs и позволить вызывающей стороне иметь дело с неверным приведением, вызванным неправильным использованием метода - при условии, что они могут его получить.скомпилировать вокруг вашего extends AbstractDO предложения.Это приводит к нежелательному побочному эффекту, заставляя потребителя обернуть вызов в блок try / catch или объявить свое собственное предложение throws, чтобы заставить блок try / catch подняться выше по стеку.

Вы можете просто проглотить исключение с пустым блоком catch;честно говоря, я бы предпочел @SuppressWarning над этим.

Или вы можете отказаться от метода целиком и иметь дело только с абстрактными сущностями, эффективно заставляя потребителя вашего репозитория иметь дело с актерами.

Итог: эти проблемы будут возникать всякий раз, когда вы будете пытаться создавать общие репозитории.Возможно, вам будет лучше с шаблоном «тип конкретного репозитория на объект».

1 голос
/ 17 сентября 2010

Во-первых, ваш код небезопасен.Он может генерировать исключение приведения класса во время выполнения.У вас должно быть

  private void saveConcreteDOs(AbstractDO[] theEntities) {        
    entityMap.put(<b>theEntities.getClass().getComponentType()</b>, 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() скрывает предупреждение для нас, вот и все.

Это не помогает версии массива, в 1011 * нет 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);
1 голос
/ 16 сентября 2010

Вы можете избежать неконтролируемого приведения, сделав свой класс общим, например,

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