programing

형식 안전:체크되지 않은 캐스팅

prostudy 2022. 7. 3. 09:51
반응형

형식 안전:체크되지 않은 캐스팅

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

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

이클립스에서 경고문구를 봤어요

형식 안전:오브젝트에서 해시 맵으로의 오프캐스트 <String, String>

뭐가 잘못됐지?

문제는 캐스트가 런타임 검사라는 것입니다. 그러나 유형 삭제로 인해 런타임에는 실제로 두 개의 차이점이 없습니다.HashMap<String,String>그리고.HashMap<Foo,Bar>다른 어떤 경우에도Foo그리고.Bar.

사용하다@SuppressWarnings("unchecked")코를 잡으세요.아, 그리고 Java에서 제네릭을 재현하기 위한 캠페인 :)

음, 우선, 당신은 새로운 것 때문에 기억을 낭비하고 있어요.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");
}

당신은 아마 이 경고를 계속 받을 것입니다.문제는...getBean돌아온다Object그래서 어떤 타입인지 알 수 없습니다.변환하다HashMap두 번째 케이스에서는 직접 문제가 발생하지 않습니다(또한 첫 번째 케이스에서는 경고가 발생하지 않을 수도 있습니다.Java 컴파일러가 Java 5에 대해 얼마나 경고를 받고 있는지 잘 모르겠습니다).단, 이 값을 변환하고 있습니다.HashMap<String, String>.

HashMaps는 객체를 키로 하고 객체를 값으로 하는 맵입니다.HashMap<Object, Object>네가 그럴 거라면.따라서, 당신이 당신의 콩을 얻었을 때 그것이 표현될 수 있다는 보장은 없습니다.HashMap<String, String>왜냐하면 네가 할 수 있었기 때문이다.HashMap<Date, Calendar>반환되는 비표준 표현에는 임의의 오브젝트가 포함될 수 있기 때문입니다.

만약 코드가 컴파일 되어 실행이 가능해진다면String value = map.get("thisString");이 경고에 대해 걱정하지 마십시오.그러나 맵이 문자열 키와 문자열 값의 완전한 문자열 키가 아닌 경우ClassCastException이 경우 제네릭은 이 문제를 차단할 수 없기 때문에 런타임에 발생합니다.

위의 메시지에서 알 수 있듯이 리스트는 다음 중 하나의 리스트로 구분할 수 없습니다.List<Object>및 aList<String>또는List<Integer>.

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

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

다음을 포함합니다.

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

설명:첫 번째 유형 변환에서는 오브젝트가 목록임을 확인합니다(List 수준에서는 내부 유형을 확인할 수 없으므로).컴파일러는 목록에 어떤 개체가 포함되어 있다는 것만 알고 있기 때문에 두 번째 변환이 필요합니다.액세스 시 목록에 있는 각 개체의 유형을 확인합니다.

경고는 바로 그것이다.경고입니다.때로는 경고가 무관할 때도 있고 아닐 때도 있다.컴파일러가 문제가 될 수 있다고 생각되지만 문제가 아닐 수 있는 것에 대한 주의를 환기하기 위해 사용됩니다.

출연자의 경우, 이 경우 항상 경고를 보냅니다.특정 캐스팅이 안전하다고 확신하는 경우 다음과 같은 주석을 줄 바로 앞에 추가하는 것을 고려해야 합니다(구문은 잘 모르겠습니다).

@SuppressWarnings (value="unchecked")

getBean이 개체 참조를 반환하고 올바른 유형으로 캐스팅하기 때문에 이 메시지가 나타납니다.Java 1.5에서는 경고가 표시됩니다.이것이 바로 Java 1.5 이상의 코드를 사용하는 특성입니다.봄에는 타이프세이프 버전이 있습니다.

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

컴파일러는 (더 이상 일반적이지 않은) 타입을 인식하고 있으며 경고는 발생하지 않습니다.이것이 항상 완벽한 해결책은 아닐 수도 있고, 어떤 사람들은 이것이 범용 클래스의 목적을 망친다고 주장할 수도 있지만, 여전히 범용 클래스의 동일한 코드를 모두 재사용하고 있으며, 컴파일 시 사용할 유형을 선언하고 있습니다.

아래 코드는 안전 경고 유형을 발생시킵니다.

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

회피책

목록에 포함된 개체 유형이 확인되지 않으므로 매개 변수를 지정하지 않고 새 맵 개체를 만듭니다.

순서 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()); 
    }

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

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

또 다른 해결책으로, 만약 당신이 같은 물체를 많이 던지고 있고, 당신의 코드를 다른 것들로 어지럽히고 싶지 않다면요.@SupressWarnings("unchecked")는 주석을 사용하여 메서드를 작성하는 것입니다.이렇게 하면 캐스팅을 중앙 집중화하고 오류 가능성을 줄일 수 있습니다.

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

제가 무엇을 잘못했나요?문제를 해결하려면 어떻게 해야 하나요?

여기:

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

귀하는 일반적으로 사용하지 않으려는 레거시 방법을 사용합니다.Object:

Object getBean(String name) throws BeansException;

콩 공장에서 콩을 (싱글톤용)/생성(시제품용)하는 것을 선호하는 방법은 다음과 같습니다.

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

다음과 같은 사용방법:

Map<String,String> someMap = app.getBean(Map.class,"someMap");

컴파일은 완료되지만 아직 체크되지 않은 변환 경고가 표시됩니다.Map오브젝트는 반드시Map<String, String>물건들.

그렇지만<T> T getBean(String name, Class<T> requiredType) throws BeansException; 및 으로 여러 해야 하기 는 collection type type으로 collection type generic type을 지정해야 합니다.

으로는 직접 .BeanFactory콩을 주입하는 틀은 그대로 두도록 하세요.

bean 선언:

@Configuration
public class MyConfiguration{

    @Bean
    public Map<String, String> someMap() {
        Map<String, String> someMap = new HashMap();
        someMap.put("some_key", "some value");
        someMap.put("some_key_2", "some value");
        return someMap;
    }
}

콩 주입:

@Autowired
@Qualifier("someMap")
Map<String, String> someMap;

언급URL : https://stackoverflow.com/questions/262367/type-safety-unchecked-cast

반응형