2015-03-08 2 views
3

У меня есть следующий код:Почему это непроверенный актер? И как это исправить?

public final <T extends Component> T getComponent(Class<T> type) { 
    Iterator<Component> it = components.iterator(); 

    while(it.hasNext()) { 
     Component next = it.next(); 

     if(type.isAssignableFrom(next.getClass())) 
      return (T)next; // Why is this an unchecked cast from Component to T? 
    } 

    return null; 
} 

И по какой-то причине, return (T)next; является неконтролируемым литым из компонента Т.

Я не уверен, почему это, потому что T должна простираться Компонент, он должен иметь возможность безопасно применять его для любых подклассов Component, правильно?

Если я вручную делаю return (TestComponent)next; и меняю тип возврата на TestComponent, он отлично работает, так почему же он не работает с T?

ответ

2

другие описали проблему, вот решение (с чистым тестом):

if(type.isInstance(next) { 
    return type.cast(next); 
} 
1

В T является подклассом компонента, каждый Т представляет собой компонент, но не каждый компонент является Т.

Если подкласс наследует от суперкласса, отливка суперкласса к подклассу не может быть выполнен успешно.

Поэтому новый компонент не может быть приведен к экземпляру T.

+0

я вижу, однако в моем случае строки '' если (type.isAssignableFrom (next.getClass())) { '' убеждается '' next'' имеет тип '' T'' правильно? – Snakybo

+0

Да 'isAssignableFrom()' проверяет, является ли тип одинаковым или является суперклассом/суперинтерфейсом 'next.getClass()'. Поэтому, если 'T' - это тот же тип, что и« Компонент », это вернет true, но вы по-прежнему не можете использовать« Компонент »для экземпляра' T', так как не каждый «Компонент» будет экземпляром 'T', и поэтому компилятор не допускает этого. –

+0

Я вижу, так что технически это было проверить, если '' next'' был экземпляр '' T'', но при компиляции не знает, что, таким образом, давая предупреждение. – Snakybo

1

Это неконтролируемый бросок, потому что компилятор не может быть уверен, что next является T. Все, что он знает, это то, что это Component.

Что касается вашего вопроса о том, почему литье в T генерирует предупреждение, но не литье в TestComponent, это намного более тонкое. Литье до TestComponent по своей сути менее изворотливое, чем литье до T. Если test не TestComponent, бросок к TestComponent вызовет ClassCastException во время выполнения. Но это не так для литья в T, так как тип T не известен во время выполнения, из-за типа стирания. Если вы внесете Component, который не является T, T, а затем добавьте результат в List<T>, у вас будет List<T>, где не все товары: T s. Это нарушит гарантию, которую генерируют генерики. Не было бы шансов на то, что это предотвратит ClassCastException.

В вашем случае, вам не нужно беспокоиться. Вы проверили бросок на T, безопасно, передав объект Class<T> и выполнив проверку. У вас есть два варианта. Вы можете подавить предупреждение и добавить комментарий, объясняющий, почему это безопасно. Однако лучшей альтернативой было бы вместо этого написать return type.cast(next);. Это не вызывает предупреждения, потому что type.cast(object)будет выбросить ClassCastException, если object не были T.

+0

Помог ли downvoter прокомментировать? –

+0

Неправильно использовать @SuppressWarnings, по той же причине не всегда правильно делать «catch (Exception)». «Я уверен, что я не ошибся» - это не очень хорошая причина; люди ошибаются, а методы впоследствии меняются. – VGR

+0

@ VGR Это чепуха. Если вы можете доказать, что что-то безопасно, вполне нормально подавлять предупреждение и добавлять комментарий, объясняющий, почему все в порядке. В любом случае, это совет Джоша Блоха в Effective Java. –

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