"TypeToken 컬렉션"이 Typesafe로 간주되는 이유는 무엇입니까?(효과적인 자바 #29)
-
21-12-2019 - |
문제
항목 #29 Effective Java에서는 "유형이 안전한" 이기종 컬렉션을 구현하는 방법을 제시합니다. 이는 기본적으로 다음과 같이 요약됩니다.
public Class HeterogeneousContainer {
private Map<Class<?>, Object> container = new HashMap<>();
public <T> put(Class<T> type, T instance) {
container.put(type, instance);
}
public <T> T get(Class<T> type) {
//essentially just
// return (T) container.get(type);
return type.cast(container.get(type));
}
}
그러면 (제 생각에) 다음과 같이 (생산자에 의해) 사용됩니다:
List<HeterogeneousContainer> resultSet = new ArrayList<>();
...
resultSet.add(new HeterogeneousContainer());
...
resultSet.get(rowIndex).add(Column1.class, column1Value);
resultSet.get(rowIndex).add(Column2.class, column2Value);
...
그리고 (소비자에 의한) 다음과 같습니다:
for(HeterogeneousContainer row:resultSet) {
Column1 column1Value = row.get(Column1.class);
Column2 column2Value = row.get(Column2.class);
...
//do something with the columnValues
}
이제 내 질문은 이것이 유형 안전으로 간주되는 이유입니다.열 이름을 맵에 넣거나 일반 이름을 사용하는 것보다 이것이 더 나은 점은 무엇입니까? List
/List<Object>
그리고 인덱스로 열을 찾으시나요?
이것이 JDBC ResultsSets의 .getString/.getInt/.getXXXX 접근 방식을 어떤 방식으로든 효과적으로/실질적으로 개선합니까?
해결책
이 클래스는 런타임 중에 클래스 캐스팅을 수행하는 동안에도 이 안전하지 않은 동작이 캡슐화되어 관찰할 수 없기 때문에 형식이 안전한 것으로 간주됩니다.
- 그만큼
container
필드는 비공개이므로 유형 안전성을 고려할 때 이 클래스 내부의 코드만 확인하면 됩니다. - 그만큼
put
메소드는 type 태그 쌍을 삽입합니다.T
그리고 유형의 요소T
.이곳이 유일한 곳이다.container
업데이트되며 삽입된 요소에 올바른 유형 태그가 있음이 (컴파일 시) 보장됩니다. - 그만큼
get
방법 하다 안전하지 않은 방식으로 클래스 캐스팅(return type.cast(container.get(type))
) 그러나 그것이 확실하다면container
를 통해서만 수정됩니다.put
, 실패할 수 없습니다.그리고 위에서 우리는 그것을 보았습니다.put
물론 그렇게 할 수 있는 유일한 방법은 이 수업입니다. ~이다 사용자에게 형식이 안전합니다.
진실을 말하자면, 정말로 원한다면 리플렉션을 사용하여 이 클래스의 유형 안전성을 깨뜨릴 수 있습니다.일반적으로 이것은 중요하지 않습니다. 왜냐하면 당신은 당신의 클래스를 방어하기를 원하기 때문입니다. 실수로 오용됨 오히려 의도적으로 손상됨.그러나, 당신이 읽어보면 효과적인 자바 게다가 그러한 공격을 방어하는 것이 훨씬 더 복잡하다는 것을 알게 될 것입니다.
제휴하지 않습니다 StackOverflow