2009-05-16 3 views
49

java.util.Properties 클래스는 키와 값이 모두 String 인 맵을 나타 내기위한 클래스입니다. 이는 Properties 개체가 텍스트 파일 인 .properties 개의 파일을 읽는 데 사용되기 때문입니다.java.util.Properties가 Map <Object, Object>를 구현하고 Map <String, String>을 구현하지 않는 이유

Java 5에서 Map<Object,Object>을 구현하고 Map<String,String>을 구현하지 않는 이유는 무엇입니까?

javadoc 상태 :

속성 해시 테이블로부터 상속 때문에 putAll에 넣어 및 방법은 객체 속성에 적용될 수있다. 호출자가 키 또는 값이 String이 아닌 항목을 삽입 할 수 있으므로 사용하지 않는 것이 좋습니다. 대신 setProperty 메소드를 사용해야합니다. String 또는 String이 아닌 키 또는 값이 포함 된 "손상된"Properties 객체에서 store 또는 save 메서드가 호출되면 호출이 실패합니다.

키와 값 모두 String이어야하기 때문에 적절한 제네릭 형식을 사용하여 정적으로 적용하지 않는 이유는 무엇입니까?

Properties 구현 Map<String,String>은 사전 Java 5 용으로 작성된 코드와 완전히 역 호환되지 않을 것입니다. 비 문자열을 Properties 객체에 붙여 넣은 코드가 있으면 Java 5에서 더 이상 컴파일하지 않습니다. 하지만 ... 그게 좋은 것 아닌가요? generics의 전체 요점이 컴파일 타임에 이러한 유형 오류를 잡아 내지는 않습니까?

답변

50

그들은 자바 초기에 서둘러 그것을했기 때문에 나중에 4 가지 버전의 의미가 무엇인지 알지 못했습니다.

제네릭은 처음부터 자바 디자인의 일부로 여겨지지만 기능이 너무 복잡하고 시간이 필요하지 않게되었습니다. 결과적으로 표준 라이브러리의 많은 코드는 비 제네릭 컬렉션의 가정으로 작성됩니다.마틴 오데 스키 (Martin Odersky)의 프로토 타입 언어 "피자 (Pizza)"는 Java 코드와 바이트 코드를 사용하여 거의 완벽한 하위 호환성을 유지하면서 어떻게 잘 수행되는지 보여주었습니다. 이 프로토 타입은 Java 5로 이어졌습니다. Java 5에서는 컬렉션 클래스가 이전 코드가 계속 작동 할 수 있도록 제네릭으로 개조되었습니다. 그들은 소급 Map<String, String>에서 Properties 상속을한다면

불행하게도, 다음 이전에 유효한 코드는 작동하지 않을 것입니다 :

Map<Object, Object> x = new Properties() 
x.put("flag", true) 

사람이 그렇게 할 것입니다 왜 나를 넘어이지만, 이전 버전과의 호환성을위한 Sun의 방침에 자바는 영웅 넘어 무의미 해졌다.

현재 대부분의 교육받은 관찰자는 Properties이 결코 Map에서 상속되어서는 안된다는 것을 알고 있습니다. 그 대신에 Map을 감싸고, 의미가있는 Map의 기능 만 표시합니다.

Martin을 재 작성한 Martin Odersky는 새로운 스칼라 언어를 만들었습니다.이 스칼라 언어는 더 깨끗하고 더 많은 실수를 상속받지 않으며 여러 영역에서 새로운 토대를 만듭니다. 자바의 괴롭힘을 짜증나게하는 경우, 살펴보십시오. 등록 정보에서지도를 만들기위한

+1

사실 맵 x = new Properties()는 어느 쪽이든 작동합니다. 그 사람들은 properties.put ("flag", Boolean.TRUE); 저는 사람들이 모든 종류의 데이터를 Properties 객체에 넣었지만 결코 String이 아닌 키는 쓰지 않는 것을 보았습니다. ;) –

+0

나는 그 대답을 더 명확하게 해주도록 고맙습니다. –

+5

잠깐! Map x = new Properties()는 Java 5에서 사전에 유효하지 않습니다. 구문은 Java 5에서 도입되었습니다. 따라서 "이전에 유효한 코드"라는 문장이 올바르지 않습니다. –

2

이유 : Liskov substitution principle 및 이전 버전과의 호환성. PropertiesHashtable을 확장하므로 Hashtable이 수락 할 모든 메시지를 수락해야합니다. 즉, put(Object, Object)을 수락한다는 의미입니다. 제네릭은 type erasure을 통해 하위 호환 방식으로 구현되었으므로 대신 일반 Hashtable을 확장해야하므로 컴파일러가 해당 작업을 완료하면 제네릭이 없습니다.

+3

나는 Liskov 대체 원칙은 그것과 아무 상관이 있다고 생각하지 않습니다. Java를 사용하면 클래스를 상속 할 때 제네릭 형식을 쉽게 수정할 수 있습니다. 그래서 구문이 존재합니다. –

27

원래 Properties이 실제로 Hashtable<String,String>으로 확장 될 예정이었습니다. 불행히도 브리지 메소드 구현으로 인해 문제가 발생했습니다. 이러한 방법으로 정의 된 Properties은 javac에서 합성 메소드를 생성합니다. Properties은 예를 들어 String을 반환하지만 Object을 반환하는 메서드를 재정의해야하는 get 메서드를 정의해야합니다. 그래서 합성 교량 방법이 추가되었습니다.

나쁜 1.4 일 동안 수업을 작성했다고 가정합니다. Properties에서 몇 가지 메소드를 재정의했습니다. 그러나 당신이하지 못한 일은 새로운 방법보다 우선합니다. 이로 인해 의도하지 않은 동작이 발생합니다. 이러한 브리지 방법을 피하기 위해 PropertiesHashtable<Object,Object>까지 확장됩니다. 마찬가지로 Iterable은 (읽기 전용) SimpleIterable을 반환하지 않습니다. 이는 Collection 구현에 메서드를 추가했기 때문입니다.

+2

좋은 설명. 나는 이것에 대해서도 궁금해했다. –

13

한 - 라이너 (경고없이 두 - 라이너) :

@SuppressWarnings({ "unchecked", "rawtypes" }) 
Map<String, String> sysProps = new HashMap(System.getProperties()); 
+0

질문에 대답하지 않습니다. 그러나 처음에는 질문의 원인이 무엇인지 대답합니다. 바로 그 지점으로. –

+1

"rawtypes"가 여기에 필요합니까? (적어도 내 IntelliJ IDEA에서는 "unchecked"로 경고를하지 않아도됩니다.) – Jonik

관련 문제