2009-09-30 5 views
17

하나의 유형 객체 만 포함하도록 보장 된 목록이 있습니다. 이것은 업데이트 할 수없는 라이브러리의 기본 코드에 의해 생성됩니다. 들어오는 목록 개체를 기준으로 <ObjectType>을 작성하여 호출 코드가 List <ObjectType>과 대화하고 있음을 확인합니다.Java 1.5에서 일반 목록 유형을 일반 목록 유형으로 변환

목록 (또는 다른 개체 컬렉션)을 <ObjectType> 목록으로 변환하는 가장 좋은 방법은 무엇입니까?

답변

13

, 일반적인 유형의 입력 매개 변수를 지정 와일드 카드를 사용하지 않는 레거시 코드와 상호 운영. 예를 들어, 당신은 단순히 반환 이전 라이브러리에서 메소드를 호출한다고 가정 Collection 원료 :

Collection<?> items = widget.getItems(); 

이를 :

코드에서
Collection getItems(); 

이 와일드 카드로 선언 된 변수에 결과를 할당 여러분은 타입 안전을 유지하므로 경고를받지 못합니다.

레거시 코드는 제네릭 매개 변수를 지정해야합니다 (주석에 있음). 예를 들어 :

/** 
* @return the items, as a Collection of {@link Item} instances. 
*/ 
Collection getItems(); 

이 경우, 당신은 선택할 수 있습니다. 으로 결과를 Collection<Item>으로 캐스팅합니다. 그렇다면 타사 라이브러리에 100 % 의존하고 Java 일반 유형의 보증을 폐기합니다. 런타임시 발생하는 ClassCastException은 명시 적으로 발생합니다 캐스트.

타사 라이브러리를 완전히 신뢰하지는 않지만 여전히 Collection<Item>을 생성해야하는 경우 어떻게해야합니까? 그런 다음 새 컬렉션을 만들고 원하는 유형으로 캐스팅 한 후 내용을 추가하십시오. 그렇게하면 라이브러리에 버그가있는 경우 코드를 멀리두고 멀리 나중에 신비하게 ClassCastException을 사용하는 것보다 즉시 발견 할 수 있습니다. 예를 들어

: 유형 매개 변수가 컴파일 시간에 알 수없는 경우를 들어

Collection<?> tmp = widget.getItems(); 
Collection<Item> items = new ArrayList<Item>(tmp.size()); 
for (Object o : tmp) 
    items.add((Item) o); /* Any type error will be discovered here! */ 

, 당신은 Collections 클래스의 type-checked collection factories를 사용할 수 있습니다.

+0

문제는 "원시 유형"경고를 억제하는 것 외에 다른 것을 얻지 못한다는 것입니다. 제네릭으로 변환하면 그 이점을 활용할 수 있습니다! –

+1

제네릭의 이점은 무엇입니까? 코드가 예쁘게 보이고 타이핑이 덜 필요하지 않습니다! * 경고없이 컴파일하면 코드가 유형 안전성이 보장됩니다. 경고를 무시하거나 억제하면 generics를 전혀 사용하지 않을 수도 있습니다. 왜냐하면 캐스트 연산자가없는 코드가 신비하게 ClassCastException을 발생시키는 상황을 만들기 때문입니다. – erickson

11

당신은 단순히 목록을 캐스팅 할 수 있습니다

List raw = new ArrayList(); 
    List<String> generic = (List<String>) raw; 
+2

목록에 실제로 한 가지 유형의 항목이 담긴다면 이것이 좋은 대답입니다. –

+1

큰 "if"입니다. 문맥에 따라 크게 달라집니다. – erickson

+0

목록에 한 유형의 항목이 들어갈 수 있습니다. 이것은 Java 1.4 사전 제네릭으로 작성된 코드입니다. –

1

가장 안전한 방법은 이전 목록의 모든 항목이 빠르면 확인됩니다,이 방법 Collections의 방법 'checkedList (목록리스트, 클래스 형)'

을 사용하는 것입니다 가능한.

+0

Java 5의'checkedList'는 새로운 (그리고 빈) generic 목록에만 적용됩니까? Java 5 이전에 비 일반 'checkedList'를 사용하도록 제안 하시겠습니까? 이 레거시 양식은 일반 목록으로 변환되지 않습니다. –

0

이전 장소에서 List<T>으로 캐스트하면 "확인되지 않은"컴파일러 경고가 표시됩니다. 우리는 이것을 유틸리티 메소드로 옮겨서 해결했습니다.

public class Lists { 
    @SuppressWarnings({"unchecked"}) 
    public static <T> List<T> cast(List<?> list) { 
     return (List<T>) list; 
    } 
} 

발신자에게 경고 메시지가 표시되지 않습니다.:

for (Element child : Lists.<Element>cast(parent.getChildren())) { 
    // ... 
} 

checkedList 그 유틸리티는 이론적으로 좋은 생각이지만, 실제로 당신이 기대하는 클래스를 전달해야 할 안됐다. Java가 런타임 일반 입력 정보를 얻길 바랍니다.

List<ObjectType> objectsWithType = Arrays.asList((ObjectType[])wildcardObjects).toArray()); 

을하지만이 고정 된 길이의 목록을 생성 할 것이라는 점을 기억하십시오

1

이보십시오. 이 목록에서 요소를 추가하거나 제거하려고하면 오류가 발생합니다. 따라서 Arrays.asList()을 사용하는 동안 항상주의하십시오.