2010-09-16 2 views
3

Есть ли способ, чтобы избежать использования @SuppressWarnings ниже и сохранить такую ​​же функциональность без предупреждения 'безопасности Типа: Переполнение отлито из AbstractDO [] Е []:Есть ли способ избежать @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

+5

Массивы и дженерики не смешиваются хорошо, лучше использовать List вместо этого. – starblue

+0

спасибо, это вариант. – topchef

ответ

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

+1

Побей меня; Я собирался сказать, что в любое время, когда вы отбрасываете родителя на ребенка, вы всегда получите это предупреждение, потому что компилятор не может гарантировать совместимость типов. –

+0

Вы имеете в виду аннотацию @SuppressWarnings, которая повлияет на поведение во время выполнения? (независимо от того, выполнялось ли «бросок»). Правильно ли я понимаю вас? Теперь это новости. –

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 [], когда я вызываю его с X.class в качестве аргумента, поэтому карта будет содержать одну запись с каждым классом и соответствующим массивом. Вы предлагаете использовать все массивы подкласса E ... – helios

+0

Правильно, helios. – topchef

+0

@grigory, то вы не можете уйти без неконтролируемого актера. –

1

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

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

Вы можете иметь только однородные массивы во время выполнения, а элемент [0] имеет тот же тип, что и тип компонента массива. Тем не менее, нет никакого способа узнать, что, изучая этот класс в одиночку.

С помощью этого исправленного кода супер-умный компилятор может доказать, что getConcreteDOs() является безопасным по типу. Однако джавак не такой умный. Для спецификации языка требуется бросить предупреждение.

Как правило, нет способа выразить более сложные отношения между ключами и значениями на 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); 
+0

Я согласен с тем, что избежать предупреждения и '@ SupressWarnings' не является самоцелью. Цель состоит в том, чтобы иметь четкий, достаточный и понятный код. Вот почему мне нравится ваш «Не бойтесь безответного предупреждения о броске, если вы знаете, что делаете, и тщательно изучили свою программу, чтобы обеспечить безопасность типа». – topchef

+0

Первая заметка о безопасности типов для меня непонятна. Как возможно, что 'theEntities [0] .getClass()' не может быть применено к классу '? – topchef

+0

@grigory say B является подклассом A, если 'array = new A [] {new B(), new A()}', ваш код будет считать, что массив является 'B []' – irreputable

Смежные вопросы