[java] 유형 안전 : 검사되지 않은 캐스트

내 봄 응용 프로그램 컨텍스트 파일에는 다음과 같은 것이 있습니다.

<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");

이클립스에서는 다음과 같은 경고가 표시됩니다.

유형 안전 : Object에서 HashMap으로 캐스트되지 않은 캐스트

내가 뭘 잘못 했어? 문제를 어떻게 해결합니까?



답변

글쎄, 우선, 당신은 새로운 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");
}

여전히이 경고가 표시 될 것입니다. 문제는 getBeanreturns Object이므로 유형이 무엇인지 알 수 없습니다. 그것을 HashMap직접 변환해도 두 번째 경우에는 문제가 발생하지 않을 것입니다 (첫 번째 경우에는 경고가 없을 것입니다 .Java 컴파일러에 Java 5에 대한 경고가 얼마나 실용적인지 잘 모르겠습니다). 그러나 당신은 그것을로 변환하고 HashMap<String, String>있습니다.

HashMaps는 실제로 객체를 키로 사용하고 객체를 값으로 갖는 맵 HashMap<Object, Object>입니다. 따라서 Bean을 얻을 때 리턴되는 비 제네릭 표현에 오브젝트가 HashMap<String, String>있을 수 있기 때문에 Bean으로 표시 될 수 있다는 보장이 없습니다 HashMap<Date, Calendar>.

코드가 컴파일되고 String value = map.get("thisString");오류없이 실행할 수 있으면이 경고에 대해 걱정하지 마십시오. 그러나 맵이 문자열 키에 대한 문자열 키로 완전히 구성되지 않은 경우, ClassCastException제네릭이이 경우 발생하는 것을 막을 수 없기 때문에 런타임에 얻을 수 있습니다.


답변

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

사용 @SuppressWarnings("unchecked")하고 코를 누르고 있습니다. 아, 그리고 자바의 제네릭에 대한 캠페인 🙂


답변

위의 메시지에서 알 수 있듯이 목록은 a List<Object>와 a List<String>또는 a로 구별 할 수 없습니다 List<Integer>.

비슷한 문제 로이 오류 메시지를 해결했습니다.

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

다음과 같이 :

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

설명 : 첫 번째 유형 변환은 오브젝트가 보유한 유형을 고려하지 않고 목록인지 확인합니다 (목록 레벨에서 내부 유형을 확인할 수 없기 때문에). 컴파일러는 List에 일종의 객체가 포함되어 있음을 알고 있으므로 두 번째 변환이 필요합니다. 그러면 액세스 할 때 List의 각 개체 유형이 확인됩니다.


답변

경고는 바로 그것입니다. 경고. 때때로 경고는 관련이 없으며 때로는 그렇지 않습니다. 컴파일러가 문제가 될 수 있지만 그렇지 않을 수도 있다고 생각하는 것에주의를 기울이는 데 사용됩니다.

캐스트의 경우이 경우 항상 경고가 표시됩니다. 특정 캐스트가 안전하다고 확신하는 경우 줄 바로 앞에 다음과 같은 주석을 추가하는 것이 좋습니다 (구문을 잘 모르겠습니다).

@SuppressWarnings (value="unchecked")


답변

getBean이 오브젝트 참조를 리턴하고 올바른 유형으로 캐스트하기 때문에이 메시지가 표시됩니다. Java 1.5는 경고를 표시합니다. 이것이 이와 같은 코드로 Java 1.5 이상을 사용하는 특성입니다. 스프링은 typesafe 버전을 가지고 있습니다

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

할 일 목록에 있습니다.


답변

실제로 경고를 제거하려면 일반 클래스에서 확장되는 클래스를 작성해야합니다.

예를 들어, 사용하려는 경우

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

당신은 같은 새로운 클래스를 만들 수 있습니다

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

그런 다음 사용하면

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

컴파일러는 (더 이상 일반적인) 유형이 무엇인지 알고 있으며 경고는 없습니다. 이것은 항상 완벽한 해결책은 아니지만 일부는 이런 종류의 제네릭 클래스의 목적을 무효화한다고 주장 할 수도 있지만 제네릭 클래스의 동일한 코드를 모두 재사용하고 있으며 컴파일 타임에 어떤 유형을 선언하고 있습니까? 사용하고 싶습니다.


답변

확인되지 않은 경고를 피하기위한 해결책 :

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");