2008-11-04 4 views
185

내 스프링 응용 프로그램 컨텍스트 파일에서 다음과 같은 내용이 있습니다.유형 안전성 : 체크되지 않은 캐스트

<util:map id="someMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String"> 
    <entry key="some_key" value="some value" /> 
    <entry key="some_key_2" value="some value" /> 
</util:map> 

Java 클래스에서 구현은 다음과 같습니다.

private Map<String, String> someMap = new HashMap<String, String>(); 
someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap"); 

Eclipse에서 다음과 같은 경고가 표시됩니다.

타입 안전성 : Object에서 HashMap으로의 체크되지 않은 캐스트

무엇이 잘못 되었습니까? 문제를 어떻게 해결합니까?

+0

관련/속는을 값을 설정 : [I을 선택하지 캐스트 경고를 해결하려면 어떻게합니까?] (http://stackoverflow.com/q/509076) – blahdiblah

+0

가능한 중복 [체크되지 않은 캐스트 경고를 처리하는 방법은 무엇입니까?] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings) –

+0

실제로 캐스트를 확인하는 루틴을 생각해 냈습니다. 매개 변수가있는 HashMap에 검사되지 않은 캐스트 경고가 제거됩니다. [link] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings/509230#509230) "올바른"해결책이지만 논란의 여지가 있는지 여부. :) – skiphoppy

답변

211

음, 우선, 새로운 HashMap 만들기 호출로 메모리를 낭비하고 있습니다. 두 번째 줄은 생성 된 해시 맵에 대한 참조를 완전히 무시하고 가비지 수집기에서 사용할 수 있도록합니다. 그래서,하지 않는다, 그 사용 :

private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap"); 

둘째, 컴파일러는 당신이이 HashMap 경우 확인하지 않고 HashMap에 개체를 캐스팅 불평한다. 하지만 할 일이 있더라도 :

if(getApplicationContext().getBean("someMap") instanceof HashMap) { 
    private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap"); 
} 

이 경고 메시지는 계속 표시됩니다. 문제는 getBeanObject을 반환하므로 형식이 무엇인지 알 수 없습니다. HashMap으로 직접 변환해도 두 번째 경우에는 문제가 발생하지 않으며 첫 번째 경우에는 경고가 표시되지 않으므로 Java 컴파일러가 Java 5에 대한 경고와 함께 얼마나 위험한 지 잘 모르겠습니다. 그러나 이것을 HashMap<String, String>으로 변환하고 있습니다.

HashMaps는 실제로 개체를 키로 사용하고 객체를 값으로 사용하는 경우 HashMap<Object, Object>입니다. 따라서 HashMap<Date, Calendar>을 가질 수 있기 때문에 빈을 얻을 때 HashMap<String, String>으로 표시 될 수 있다는 보장이 없습니다. 반환되는 비 - 제네릭 표현에는 어떤 객체도있을 수 있기 때문입니다.

코드가 컴파일되고 오류없이 String value = map.get("thisString");을 실행할 수 있으면이 경고에 대해 걱정할 필요가 없습니다. 그러나지도가 문자열 값에 대한 문자열 키를 완전히 갖고 있지 않은 경우 실행시에 ClassCastException이 발생합니다. 왜냐하면 제네릭이이 경우 발생하지 않도록 차단할 수 없기 때문입니다.

+10

이것은 얼마 전 이었지만 캐스팅 전에 Set 을 검사하는 유형의 답을 찾고 있었고 매개 변수화 된 제네릭에서는 instanceof를 사용할 수 없습니다. 예 : if (event.getTarget instanceof Set ) 입력란에는 일반? 캐스트 경고를 제거하지 않습니다. 예 : if (event.getTarget instanceof Set ) – garlicman

21

경고는 바로 그 것입니다. 경고. 때로는 경고가 부적절하고 가끔은 그렇지 않습니다. 그들은 컴파일러가 문제라고 생각하는 것에주의를 환기시키는 데 사용되지만, 그렇지 않을 수도 있습니다.

캐스트의 경우이 경우 항상 경고를 표시합니다. 특정 캐스트가 안전 할 것이라는 확신이 있다면, 당신은 단지 라인 전에 (I 구문의 확실하지 않다) 같은 주석을 추가하는 것을 고려한다 :

@SuppressWarnings (value="unchecked") 
+8

-1 : 경고를 절대 받아서는 안됩니다. 또는 이러한 종류의 경고를 표시하지 않거나 수정하십시오. 당신이 많은 경고를해야 할 순간이 올 것이고 당신은 관련성을 한번 볼 수 없을 것입니다. – ezdazuzena

+5

매개 변수가있는 제네릭 (예 :지도)을 전송할 때 클래스 캐스트 경고를 피할 수는 없으므로 원래 질문에 대한 최상의 대답입니다. – muttonUp

9

을 당신이 메시지 때문에지고있다 getBean은 Object 참조를 반환하고 올바른 유형으로 캐스팅합니다. Java 1.5에서는 경고 메시지를 표시합니다. 이것이 Java 1.5 이상을 사용하는 코드의 특징입니다. Spring은 typesafe 버전을 가지고있다. dodo list에는 typesafe 버전이있다.

someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap"); 

이다.

248

문제는 캐스트 런타임 검사입니다 -하지만 형의 삭제로 인해 런타임에 실제로 다른 FooBar 어떤을위한 HashMap<String,String>HashMap<Foo,Bar> 사이에는 차이가 없습니다.

@SuppressWarnings("unchecked")을 사용하고 코를 잡으십시오. 아, 그리고 자바에서 구체화 제네릭 :) 메시지가 위의 표시로

+12

자바의 구체화 된 제네릭을 타입이 지정되지 않은 NSMutableWhatever에 적용 할 것입니다. NSMutableWhatever는 10 년의 도약으로 요일을 바꾸는 것처럼 느껴집니다. 적어도 자바가 노력하고 있습니다. –

+11

정확히. 형식 검사를 요구한다면 HashMap 으로 만 수행 할 수 있으며 일반 형식을 검사하지 않기 때문에 경고가 제거되지 않습니다. 그것은 세상의 종말이 아니지만, 경고를 저지하거나 그걸 가지고 살아가는 것이 잡히는 것을 성가 시게합니다. – garlicman

+1

@JonSkeet Reified generic이란 무엇입니까? – SasQ

53

위한 캠페인 목록은 List<Object>List<String> 또는 List<Integer> 사이에 구별 할 수 없습니다.

나는 비슷한 문제에 대해이 오류 메시지를 해결 한

:

List<?> strList = (List<?>) someFunction(); 
String s = (String) strList.get(0); 

설명 : 다음과

List<String> strList = (List<String>) someFunction(); 
String s = strList.get(0); 

첫 번째 유형 변환 개체에 대한 걱정없이 목록을인지 확인 내부에서 보유한 유형 (목록 수준에서 내부 유형을 확인할 수 없기 때문에) 컴파일러는 목록에 어떤 종류의 객체가 있다는 것을 알고 있기 때문에 두 번째 변환이 필요합니다. 이렇게하면 목록에있는 각 객체의 유형이 액세스 된대로 확인됩니다.

+1

당신은 내 친구입니다. 목록을 캐스팅하는 대신 목록을 반복하고 각 요소를 캐스팅하면 경고가 표시되지 않습니다. –

+0

이것은 경고를 제거했지만 여전히 자신이 아닙니다. P – mumair

4

정말로 경고를 없애려면 할 수있는 일은 제네릭 클래스에서 확장되는 클래스를 만드는 것입니다.

예를 들어

, 당신은

private Map<String, String> someMap = new HashMap<String, String>(); 

를 사용하려는 경우, 당신은 당신이

someMap = (StringMap) getApplicationContext().getBean("someMap"); 

는 컴파일러가하는 사용할 때 다음과 같은

public class StringMap extends HashMap<String, String>() 
{ 
    // Override constructors 
} 

같은 새로운 클래스를 만들 수 있습니다 더 이상 일반적인 유형이 무엇인지 알면 경고가 표시되지 않습니다. 이것은 항상 완벽한 솔루션이 아닐 수도 있습니다. 일부는 이러한 종류의 제네릭 클래스의 목적을 상실한다고 주장 할 수도 있지만, 여전히 제네릭 클래스에서 동일한 코드를 모두 다시 사용하고 있습니다. 컴파일 타임에 어떤 타입인지 당신은 사용하고 싶습니다.

1

또 다른 해결책은, 동일한 객체를 많이 캐스팅하고 코드를 @SupressWarnings("unchecked")으로 흩 뜨리지 않으려면 주석이있는 메소드를 만드는 것입니다. 이렇게하면 캐스트를 중앙 집중화하고 실수로 오류 가능성을 줄일 수 있습니다. 코드 아래

@SuppressWarnings("unchecked") 
public static List<String> getFooStrings(Map<String, List<String>> ctx) { 
    return (List<String>) ctx.get("foos"); 
} 
0

는 개체의 유형 개최하기 때문에 매개 변수를 언급하지 않고 유형 안전 경고를

Map<String, Object> myInput = (Map<String, Object>) myRequest.get();

해결

새로운지도 객체를 생성 원인 목록에서 n은 확인되었습니다.

1 단계 : 새 임시지도

만들기

Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();

2 단계 : 인스턴스화 주요지도

Map<String, Object> myInput=new HashMap<>(myInputObj.size()); 

3 단계 :으로 반복 임시지도는 기본지도로

for(Map.Entry<?, ?> entry :myInputObj.entrySet()){ 
     myInput.put((String)entry.getKey(),entry.getValue()); 
    } 
관련 문제