예를 들어, 두 개의 클래스가 있다고 가정 해 봅시다.
public class TestA {}
public class TestB extends TestA{}
나는 a를 반환하는 메소드를 가지고 List<TestA>
있으며 그 목록의 모든 객체를 캐스트 TestB
하여 a로 끝납니다 List<TestB>
.
답변
List<TestB>
거의 작업에 단순히 캐스팅 ; 그러나 한 유형의 매개 변수를 다른 유형으로 캐스트 할 수 없기 때문에 작동하지 않습니다. 그러나 중간 와일드 카드 유형을 통해 캐스트 할 수 있으며 허용되지 않습니다 (확인하지 않은 경고만으로 와일드 카드 유형과 캐스트 할 수 있으므로).
List<TestB> variable = (List<TestB>)(List<?>) collectionOfListA;
답변
제네릭 캐스팅은 불가능하지만 다른 방법으로 목록을 정의하면 TestB를 저장할 수 있습니다.
List<? extends TestA> myList = new ArrayList<TestA>();
목록의 객체를 사용할 때 유형 검사를 계속해야합니다.
답변
당신은 정말로 할 수 없습니다 * :
이 Java 자습서 에서 예를 가져옵니다.
두 가지 유형이 있다고 가정 A
하고B
같은 그 B extends A
. 그런 다음 다음 코드가 맞습니다.
B b = new B();
A a = b;
이전 코드는 B
하위 클래스 이므로 유효합니다.A
. 자, 함께 발생 List<A>
하고 List<B>
?
그것은 우리 List<B>
의 하위 클래스가 아닙니다.List<A>
쓰기
List<B> b = new ArrayList<>();
List<A> a = b; // error, List<B> is not of type List<A>
또한, 우리 는 할 수 없습니다 쓸
List<B> b = new ArrayList<>();
List<A> a = (List<A>)b; // error, List<B> is not of type List<A>
* : 우리는 모두 공통의 부모를 필요로 캐스팅을 가능하게하는 방법 List<A>
과 List<B>
: List<?>
예를 들면. 다음 은 유효합니다 :
List<B> b = new ArrayList<>();
List<?> t = (List<B>)b;
List<A> a = (List<A>)t;
그러나 경고가 표시됩니다. @SuppressWarnings("unchecked")
메소드 에 추가 하여 억제 할 수 있습니다 .
답변
Java 8을 사용하면 실제로
List<TestB> variable = collectionOfListA
.stream()
.map(e -> (TestB) e)
.collect(Collectors.toList());
답변
그래도 잘못된 방향으로 캐스팅하고 있다고 생각합니다 … 메소드가 TestA
객체 목록을 반환 하면 실제로 객체를 캐스팅하는 것이 안전하지 않습니다 TestB
.
기본적으로 컴파일러에서 지원하지 않는 TestB
유형에 대한 작업을 수행 할 수 있도록 컴파일러에 요청 TestA
합니다.
답변
이것은 널리 참조되는 질문이며, 현재 답변은 왜 작동하지 않는 이유를 설명합니다 (또는 프로덕션 코드에서 결코 보지 못했던 해킹하고 위험한 솔루션을 제안합니다). 다른 답변을 추가하는 것이 적절하다고 생각합니다. 함정 및 가능한 해결책.
이것이 일반적으로 작동하지 않는 이유는 이미 다른 답변에서 지적되었습니다. 변환이 실제로 유효한지 여부는 원래 목록에 포함 된 객체의 유형에 따라 다릅니다. 목록에 유형이 아닌의 TestB
다른 서브 클래스 인 유형의 오브젝트가 있으면 TestA
캐스트가 유효 하지 않습니다.
물론 캐스트 가 유효 할 수 있습니다. 때로는 컴파일러에서 사용할 수없는 유형에 대한 정보가 있습니다. 이 경우 목록을 전송할 수 있지만 일반적으로 권장하지 않습니다 .
하나는 …
- … 전체 목록을 캐스팅하거나
- … 목록의 모든 요소를 캐스트
첫 번째 접근 방식 (현재 허용되는 답변에 해당)의 의미는 미묘합니다. 언뜻 보면 제대로 작동하는 것 같습니다. 그러나 입력 목록에 잘못된 유형이있는 ClassCastException
경우 코드에서 완전히 다른 위치에 a가 발생하고이를 디버그하고 잘못된 요소가 목록에서 미끄러지는 위치를 찾는 것이 어려울 수 있습니다. 최악의 문제는 목록을 캐스팅 한 후 누군가가 잘못된 요소를 추가하여 디버깅을 더욱 어렵게 한다는 것 입니다.
이러한 스퓨리어스를 디버깅하는 문제는 메소드 계열 ClassCastExceptions
로 완화 할 수 있습니다 Collections#checkedCollection
.
유형을 기준으로 목록 필터링
a에서 a List<Supertype>
로 변환하는 더 안전한 형식의 방법은 List<Subtype>
실제로 목록을 필터링 하고 특정 유형의 요소 만 포함하는 새 목록을 만드는 것입니다. 그러한 방법의 구현에 대한 자유도가 어느 정도 있지만 (예를 들어 null
, 엔트리 처리와 관련하여 ), 한 가지 가능한 구현은 다음과 같습니다.
/**
* Filter the given list, and create a new list that only contains
* the elements that are (subtypes) of the class c
*
* @param listA The input list
* @param c The class to filter for
* @return The filtered list
*/
private static <T> List<T> filter(List<?> listA, Class<T> c)
{
List<T> listB = new ArrayList<T>();
for (Object a : listA)
{
if (c.isInstance(a))
{
listB.add(c.cast(a));
}
}
return listB;
}
이 방법은 다음 예제와 같이 임의의 목록을 필터링하기 위해 사용할 수 있습니다 (유형 매개 변수와 관련하여 주어진 하위 유형-슈퍼 유형 관계뿐 아니라).
// A list of type "List<Number>" that actually
// contains Integer, Double and Float values
List<Number> mixedNumbers =
new ArrayList<Number>(Arrays.asList(12, 3.4, 5.6f, 78));
// Filter the list, and create a list that contains
// only the Integer values:
List<Integer> integers = filter(mixedNumbers, Integer.class);
System.out.println(integers); // Prints [12, 78]
답변
당신은 캐스트 수 없습니다 List<TestB>
에 List<TestA>
스티브 쿠오 언급하지만 당신의 내용을 덤프 수 List<TestA>
에를 List<TestB>
. 다음을 시도하십시오 :
List<TestA> result = new List<TestA>();
List<TestB> data = new List<TestB>();
result.addAll(data);
나는이 코드를 시도하지 않았으므로 실수가있을 수 있지만 아이디어는 요소 (TestB 객체)를 List에 추가하는 데이터 객체를 반복해야한다는 것입니다. 나는 그것이 당신을 위해 작동하기를 바랍니다.