이것은 컴파일되지 않으며 어떤 제안이라도 감사합니다.
...
List<Object> list = getList();
return (List<Customer>) list;
컴파일러는 말한다 : 캐스팅 할 수 없습니다 List<Object>
에List<Customer>
이것은 컴파일되지 않으며 어떤 제안이라도 감사합니다.
...
List<Object> list = getList();
return (List<Customer>) list;
컴파일러는 말한다 : 캐스팅 할 수 없습니다 List<Object>
에List<Customer>
답변:
먼저 Object로 업 캐스팅하여 모든 객체를 모든 유형으로 캐스팅 할 수 있습니다. 귀하의 경우 :
(List<Customer>)(Object)list;
런타임시 목록에 Customer 개체 만 포함되어 있는지 확인해야합니다.
비평가들은 이러한 캐스팅이 코드에 문제가 있음을 나타냅니다. 이를 방지하기 위해 유형 선언을 조정할 수 있어야합니다. 그러나 Java 제네릭은 너무 복잡하고 완벽하지 않습니다. 런타임 유형을 잘 알고 있고 수행하려는 작업이 안전하다는 것을 알고 있더라도 컴파일러를 만족시킬 수있는 예쁜 솔루션이 있는지 알 수없는 경우가 있습니다. 이 경우 필요에 따라 원유 주조를하여 집에 직장을 떠날 수 있습니다.
@SuppressWarnings("unchecked")
. (List)
대신에 업 캐스트 할 수도 있습니다 (Object)
.
고객 은 객체 이지만 고객 목록은 객체 목록 이 아니기 때문 입니다. 그것이 경우에, 당신은 넣을 수 있는 고객의 목록에서 개체를.
.Cast<T>()
하나는 호출 되고 하나는 .OfType<T>()
. 전자는 각 요소에 대해 캐스트를 수행하고 (원하는 예외를 던짐) 후자는 캐스트 할 수없는 요소를 필터링하므로 사용 시나리오에 따라 하나를 선택합니다.
instanceof
고객 이 아닌 경우 어떻게됩니까 ?
다른 코드에 따라 가장 좋은 답변이 다를 수 있습니다. 시험:
List<? extends Object> list = getList();
return (List<Customer>) list;
또는
List list = getList();
return (List<Customer>) list;
그러나 이러한 확인되지 않은 캐스트를 수행하는 것은 권장되지 않습니다.
Java 8 Streams 사용 :
때때로 무차별 대입 캐스팅이 괜찮습니다.
List<MyClass> mythings = (List<MyClass>) (Object) objects
그러나 여기에 더 다양한 솔루션이 있습니다.
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
많은 이점이 있지만 목록에 포함 된 내용이 확실하지 않은 경우 목록을보다 우아하게 캐스팅 할 수 있습니다.
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
했습니다 .하지만 Guava가 저를 위해 일했습니다.
저는 자바 프로그래머가 아니지만 .NET 및 C #에서는이 기능을 반 변성 또는 공분산이라고합니다. 나는 아직 베타 버전이기 때문에 사용하지 않는 .NET 4.0의 새로운 기능이므로 두 용어 중 어떤 것이 문제를 설명하는지 모르겠지만 설명하겠습니다. 기술적 인 문제입니다.
캐스팅이 허용되었다고 가정 해 봅시다. 내가 말한 것이므로 cast 라고 말하지만 가능할 수있는 두 가지 작업, 캐스팅 및 변환 .
변환은 새로운 목록 객체를 얻는 것을 의미하지만 캐스팅이라고 말하면 한 객체를 일시적으로 다른 유형으로 취급하고 싶습니다.
여기에 문제가 있습니다.
다음이 허용되면 어떻게 될까요? (참고, 캐스트 전에 개체 목록에는 실제로 Customer 개체 만 포함되어 있다고 가정합니다. 그렇지 않으면이 가상 버전의 Java에서도 캐스트가 작동하지 않습니다.)
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
이 경우 고객이 아닌 개체를 고객으로 처리하려고 시도하고 목록 내부의 양식이나 할당에서 한 지점에서 런타임 오류가 발생합니다.
그러나 Generics는 컬렉션과 같은 유형 안전 데이터 유형을 제공해야하며 '보장'이라는 단어를 던지기를 좋아하기 때문에 뒤 따르는 문제가있는 이러한 유형의 캐스트는 허용되지 않습니다.
.NET 4.0 (당신의 질문은 자바에 관한 것이 었습니다)에서 이것은 매우 특정한 경우에 허용 됩니다 컴파일러가 당신이하는 작업이 안전하다는 것을 보장 할 수있는 . 그러나 일반적으로 이러한 유형의 캐스트는 그렇지 않습니다. 허용됩니다. Java 언어에 공 변성 및 반 변성을 도입 할 계획이 있는지 확실하지 않지만 Java도 마찬가지입니다.
나보다 더 나은 자바 지식을 가진 사람이 자바 미래 또는 구현에 대한 세부 사항을 알려줄 수 있기를 바랍니다.
당신 때문이 아니라 수 List<Object>
와 List<Customer>
같은 상속 트리에 있지 않습니다.
List<Customer>
a List<Object>
를 사용 하는 클래스에 새 생성자를 추가 한 다음 각각 Object
을 a로 캐스팅 Customer
하고 컬렉션에 추가 하는 목록을 반복 할 수 있습니다. 호출자가 List<Object>
.NET Framework가 아닌 무언가를 포함 하는 경우 잘못된 캐스트 예외가 발생할 수 있습니다 Customer
.
일반 목록의 요점은 특정 유형으로 제한하는 것입니다. 주문, 제품 등 무엇이든 포함 할 수 있는 목록을 가져 와서 고객 만 가져올 수있는 목록으로 압축하려고합니다.
가장 좋은 방법은 새 List<Customer>
를 만들고을 반복 List<Object>
하고 새 목록에 각 항목을 추가 한 다음 반환하는 것입니다.
다른 사람들이 지적했듯이 a List<Object>
가 List<Customer>
. 당신이 할 수있는 일은 내부 유형 검사를 수행하는 목록의 뷰를 정의하는 것입니다. 다음과 같은 Google 컬렉션 사용 :
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
위의 Bozho와 비슷합니다. 이 방법을 통해 (내 자신이 마음에 들지 않지만) 여기에서 몇 가지 해결 방법을 수행 할 수 있습니다.
public <T> List<T> convert(List list, T t){
return list;
}
예. 목록을 요구되는 일반 유형으로 캐스팅합니다.
위의 경우 다음과 같은 코드를 수행 할 수 있습니다.
List<Object> list = getList();
return convert(list, new Customer());
목록으로 수행하려는 작업에 따라 목록을 List<Customer>
. Customer
목록 에 개체 만 추가하려는 경우 다음과 같이 선언 할 수 있습니다.
...
List<Object> list = getList();
return (List<? super Customer>) list;
이것은 합법적입니다 (글쎄요, 합법적 일뿐만 아니라 정확합니다 -목록은 "고객에게 일부 상위 유형"입니다). 목록에 객체를 추가하는 메서드에 전달하려는 경우 위의 제네릭 경계면 충분합니다.
반면에 목록에서 개체를 검색하고이를 Customers로 강력하게 입력하려면 운이 좋지 않은 것입니다. 목록은List<Object>
콘텐츠가 고객이라는 보장이 없으므로 검색시 자신의 캐스팅을 제공해야합니다. (또는 목록 Customers
에 다른 답변 중 하나의 이중 캐스트 만 포함 하고 사용 한다는 것을 정말로, 절대적으로 두 배로 확신하십시오. 케이스).
광범위하게 말하면 메서드를 작성할 때 허용되는 가능한 가장 광범위한 제네릭 경계를 고려하는 것이 좋습니다. 라이브러리 메서드로 사용되는 경우 두 배입니다. 예를 들어 목록에서만 읽을 경우 List<? extends T>
대신을 사용 List<T>
하십시오. 이렇게하면 호출자에게 전달할 수있는 인수의 범위가 훨씬 더 넓어 지고 사용자 와 유사한 문제가 발생할 가능성이 적습니다. 여기에 다시 있습니다.