2010-12-08 2 views
20

다음 코드가 있습니다.java : 체크되지 않은 캐스트 경고를 수정하는 방법

private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores; 

public <T extends Component> T getComponent(Entity e, Class<T> exampleClass) 
{ 
    HashMap<Entity, ? extends Component> store = m_componentStores.get(exampleClass); 

    T result = (T)store.get(e); 

    if (result == null) 
    { 
     throw new IllegalArgumentException("GET FAIL: "+e+" does not possess Component of class\nmissing: "+exampleClass); 
    } 

    return result; 
} 

컴파일 할 때 T result = (T)store.get(e)에 검사되지 않은 캐스트가 있음을 보여줍니다.

Type safety: Unchecked cast from capture#2-of ? extends Component to T 

이 경고가 나타나지 않도록하려면 무엇이 누락 되었습니까?

답변

32

Class.cast은 원하는 것입니다. 글쎄, 당신은 반사를 사용하지 않을 수도 있습니다.

변경 라인 :

T result = (T)store.get(e); 

에 : 캐스트 문 위의

T result = exampleClass.cast(store.get(e)); 
+0

항상 +1, 더 나은 : 당신은 다음과 같은 귀하의 경우에 동일 작동 와일드 카드 캡처가 필요하지 않습니다 도서관 코드 IMO. 라이브러리가 실수를하지 않는다는 것을 증명할 수 있다면 (즉,'setComponent'는 적절하고 대칭 적으로 작동합니다.) 반드시 증명할 필요는 없습니다. 그런 다음 억제 경고가 나타납니다. –

+3

@ Mark Peters 프로그래머가 스스로를 납득시키는 대부분의 문제에서는 일반적으로 잘못되었습니다. –

+1

나는 그것이 모든 도서관 디자이너들에게는 사실이라고 생각하지 않으며, 그렇다면 도서관을 작성해서는 안된다. API에는 검사되지 않은 캐스트의 예가 있습니다. 'Collections.emptyList()'가 떠오른다. –

14

쓰기 @SuppressWarnings("unchecked") :

@SuppressWarnings("unchecked") 
T result = (T)store.get(e); 

그리고는 무시하는 것이 안전 이유를 설명 문을 추가 경고.

+0

무시해도 안전하지 않습니다. 간단한 예제를 가정 해 봅시다 :'abstract class Animal {public abstract void makeNoice(); }','class Cat은 Animal {}'을 확장하고'class Dog는 Animal {}'을 확장합니다. 'Dog'와'Cat'은 모두'Animal'입니다. Now :'class SomeAnimalUtils {public static void makeNoise (동물 동물) {개 개 = (개) 동물; dog.makeNoice(); }}'. 두 방법 모두 제대로 메소드를 구현한다고 가정 해 봅시다. 이제'SomeAnimalUtils.makeNoise()'는 원하는 Animal을 확장하기 때문에'Cat'을 취할 수 있지만'Dog'에 캐스트 할 수없고'ClassCastException'을 사용합니다. – Roland

+0

글쎄, 내 예제는 바보 여기지만 실제로 당신이 체크되지 않은 캐스트를 처리 할 필요가 입증해야합니다. 사람들이'Cat'을'Dog' ('Terrier' 또는'Husky'와 같은 다른 클래스의 슈퍼 클래스가 될 수 있음)에 넣는 것을 막기 위해. 그러나 누군가 JVM에서 의도하지 않은'Cat'을 주면 예외를 던집니다. 'SomeAnimalUtils' 프로그래머가 매개 변수를 검사하지 않고 hilfself에 의해 예외를 throw했기 때문에 이것은 나쁘다. – Roland

+0

그래서 이것을 미리 확인해야합니다. 이렇게하려면 안전하지 않은/체크되지 않은 캐스트 앞에 다음 코드를 추가하십시오. if (null == animal) {throw new NullPointerException ("Parameter 'animal'is null"); } 새로운 ifCastException ("매개 변수 'animal'="+ animal.toString() + "Dog의 인스턴스가 아님"); }'. 자바 언어에서 "객체"매개 변수 (= 객체 또는 인터페이스)의 인스턴스로 전달할 수있는 null 참조 검사를 처리해야합니다. null 참조를 돌보지 않으면 여기에 악명 높은 NPE가 나타날 수 있습니다. – Roland

3

제네릭은 실제로 그렇게 작동하지 않습니다. T! = ? extends ComponentT extends Component. 실제로 가지고있는 것은 wildcard capture입니다. 다른 목적을 가지고 있습니다.

그리고 네 솔루션하지 입력 - 안전 -에있는 두 개의 ?마르크 사이에 관계가 없다 :

private HashMap<Class<?>, HashMap<Entity, ? extends Component>> m_componentStores; 

그래서 몇 가지를 사용하여이 구조 Component의 일부 서브 클래스의 인스턴스를 넣어 법적되고이 다른 클래스 (Component의 하위 클래스도 아님)를 키로 사용합니다.

m_componentStores는 그것이 extendsComponent 이외의 당신이 거기에있는 값의 어떤 정확한 유형을 알 수있는 방법이 없습니다 실행시에, 그래서 일반적인 유형 만 컴파일시에 해결하는 것을 기억하십시오.

그래서 당신이 store.get(e)에서 얻을 유형은 Component ...입니다 : 캐스트가 정적으로 검사 할 수 없기 때문에

당신이 TComponent 캐스팅
Component result = store.get(e); 

컴파일러는 경고를 발행합니다. 그러나 데이터 구조의 의미에 대해 확신이 있다면 단순히 경고를 표시하지 않을 수 있습니다.

@SuppressWarnings("unchecked") 
    T resultT = (T)result; 

추신 :에 ClassCastException이 유지

private HashMap<Class<?>, HashMap<Entity, Component>> m_componentStores; 
관련 문제