2017-10-20 2 views
5

오늘 나는 객체가 올바른 유형으로 형 변환 될 수 없더라도 기존 Map에있는 객체를 put 수 있다고 발견했습니다.초기화 된 맵에 일치하지 않는 유형의 객체를 넣는 - 예상되고 합법적입니까?

먼저, 내가 간단한 예제로 시작하자 : 당신이 하지가 이미 구축지도에 일관성이 형식의 개체를 넣을 수있을 것 같은

Map<Integer, String> myMap = new HashMap<>(); //plain old hashmap 
myMap.put(9,"star"); //no problem 

myMap.put(10, 1.2); //Incompatible type, the compiler yells 
Map<Integer, Double> aMap = (Map<Integer, Double>) myMap; //Cannot cast, the compiler yells 

지금까지, 모든 것이 예상된다. 지도는 이것을 달성, 그리고 않는 방법 JLS 또는 API에 지정된이 동작하며, 따라서 의존 할 수있다 -

public class NoRulesForMe { 

    static Object theRing; 

    public static void main(String[] args){ 

     Map<Integer, String> myMap = new HashMap<>(); 
     myMap.put(9,"star"); 

     Map<Integer, Double> myMapMorphed = castWildly(myMap); 
     myMapMorphed.put(99, 3.14); 

     System.out.println(myMapMorphed.get(9)); //"star", as we put in 
     System.out.println(myMapMorphed.get(99)); //3.14, as we put in 
    } 

    public static <T> T castWildly(Object value){ 
     theRing = value; 
     T morphed = (T) theRing; 
     return morphed; 
    } 
} 

나는이 런타임 오류가 발생하지 않았다 놀랍가 : 이제이 문제를 살펴 보자 ?

이유 나는 이것이 프로덕션 코드에서 (더 복잡한) 버전을 보았고, 이것이 어수선하고 냄새가 심할지라도 기능적으로 작동하도록 보장 할 수 있는지 궁금합니다. 모든 입력을 부탁드립니다.

+0

Google "입력 삭제"가 필요합니다. –

+0

이것은 Java가 제네릭을 구현할 때 _inherent_입니다. –

+0

@ 루이스 와서 만 Java generics에 내재 된 * 내용을 자세히 설명해 주시겠습니까? 나는 컴파일러가 불평하지 않았다는 것에 놀랄 필요가 없다. 하지만 더 큰 질문은 Java가'Double'을'String'으로 저장하는 방법입니다. – flow2k

답변

1

이 코딩 유형은 매우 위험합니다! 컴파일되지만 컴파일러가 경고 메시지를 표시합니다.

참고 : NoRulesForMe.java는 검사되지 않거나 안전하지 않은 작업을 사용합니다.
참고 : 자세한 내용은 -Xlint :를 사용하여 다시 컴파일하십시오.

이러한 경고는 특히 제네릭을 사용하고 있으므로 무시하거나 절대로 표시해서는 안됩니다. 캐스트가 안전하고 나중에 문제가 발생하지 않을 것임을 절대적으로 확신해야합니다 (논리적으로 코드를 따르십시오). 런타임에 컴파일러 시간에 오류가 발견되고 선택되도록 항상 코드를 작성하는 것이 가장 좋습니다. 여기 컴파일러가 경고하는 것은 상황이 잘못 될 수도 있음을 알려주는 것입니다.

당신이 MapObject에서 캐스팅 캐스팅하여 myMap 방법 castWildly, 그리고 경우에 Object int로서 당신은 지나가는

.

컴파일러는 코드의 TMap<String, Double>의 유형 타겟을 갖고 있다고 추론 할 수 있으므로이를 추론 할 수 있습니다. 그러나 캐스팅 할 때 Object value (또는 Object theRing)이 어떤 (하위) 유형인지에 대한 정보가 없습니다. 따라서 캐스트가 안전하다는 것을 확인하는 방법이 없습니다 (특히 유형 안전).

이 코드의 문제점은 맵에서 값을 검색 할 때 발생합니다. 다음 코드에는 추가 된 행이 하나 더 있으며 코드가 컴파일됩니다 (위와 같은 경고와 함께). 이는 Double (지도에서 Map<String, Double>으로 선언 된 값을 검색 할 때 컴파일러가 유형 검사를 수행 할 때 절대적으로 유효하기 때문입니다 ... 그러나 런타임에는 코드가 충돌합니다 (런타임 오류 오류가 아래에 표시됨). 이것은 특히 프로덕션 코드에서 매우 위험한 코드 작성 방법입니다. 컴파일러에서 컴파일 할 생산 코드를 배포하는 것보다 오류가 발생하는 경우 제품 오류가 발생할 수 있습니다. 위의 코드를 실행

public class NoRulesForMe { 

    static Object theRing; 

    public static void main(String[] args){ 

     Map<Integer, String> myMap = new HashMap<>(); 
     myMap.put(9,"star"); 

     Map<Integer, Double> myMapMorphed = castWildly(myMap); 
     myMapMorphed.put(99, 3.14); 

     System.out.println(myMapMorphed.get(9)); //"star", as we put in 
     System.out.println(myMapMorphed.get(99)); //3.14, as we put in 

     // added to show why this style of coding causes problems 
     Double testValue1 = myMapMorphed.get(9); 
    } 

    public static <T> T castWildly(Object value){ 
     theRing = value; 
     T morphed = (T) theRing; 
     return morphed; 
    } 
} 

실행 시간 오류 :

스타
3.스레드에서 14
예외 "주요"java.lang.ClassCastException가 : 자세한 내용은 java.lang.String의가 NoRulesForMe.main에서 java.lang.Double에 캐스트 할 수없는 (NoRulesForMe.java:19)

Joshua Bloch의 Effective Java 읽기. 항목 24 : 확인되지 않은 경고를 제거하십시오. (이 항목은 제네릭이라는 제목 아래에 있습니다).

관련 문제