List <Object>를 List <MyClass>로 캐스팅하는 방법


답변:


156

먼저 Object로 업 캐스팅하여 모든 객체를 모든 유형으로 캐스팅 할 수 있습니다. 귀하의 경우 :

(List<Customer>)(Object)list; 

런타임시 목록에 Customer 개체 만 포함되어 있는지 확인해야합니다.

비평가들은 이러한 캐스팅이 코드에 문제가 있음을 나타냅니다. 이를 방지하기 위해 유형 선언을 조정할 수 있어야합니다. 그러나 Java 제네릭은 너무 복잡하고 완벽하지 않습니다. 런타임 유형을 잘 알고 있고 수행하려는 작업이 안전하다는 것을 알고 있더라도 컴파일러를 만족시킬 수있는 예쁜 솔루션이 있는지 알 수없는 경우가 있습니다. 이 경우 필요에 따라 원유 주조를하여 집에 직장을 떠날 수 있습니다.


8
이것도 필요합니다 @SuppressWarnings("unchecked"). (List)대신에 업 캐스트 할 수도 있습니다 (Object).
200_success

36

고객 객체 이지만 고객 목록은 객체 목록 이 아니기 때문 입니다. 그것이 경우에, 당신은 넣을 수 있는 고객의 목록에서 개체를.


2
아니, 그렇지 않습니다. 위의 사항이 허용되면 형식 안전을 우회 할 수 있습니다. 캐스팅은 새 목록을 만들고 항목을 복사하는 것을 의미하지 않습니다. 즉, 단일 인스턴스를 다른 유형으로 처리하므로 유형 안전성이 보장되지 않는 잠재적으로 고객이 아닌 개체가 포함 된 목록을 갖게됩니다. 이것은 자바와 관련이 없습니다. 이 기능으로 인해 Java가 암흑기에 갇혀 있다고 생각하므로이 기능이 대신 작동해야한다고 생각하는 방법을 설명해 드리겠습니다.
Lasse V. Karlsen 2014 년

1
귀하의 필요에 대한 @ BrainSlugs83 (List <Customer>) (Object) list;
Muthu Ganapathy Nathan

@ LasseV.Karlsen 캐스팅에 대해 말하는 것이 아니라 변환에 대해 말하는 것입니다. 유형 안전을 우회하지 않고 강제합니다. Java의 제네릭 구현, 연산자 오버로드 부족, 확장 메서드 및 기타 여러 현대적인 편의 시설은 나를 크게 실망하게했습니다. -한편 .NET에는이를위한 두 개의 별도 확장 메서드가 있습니다. .Cast<T>()하나는 호출 되고 하나는 .OfType<T>(). 전자는 각 요소에 대해 캐스트를 수행하고 (원하는 예외를 던짐) 후자는 캐스트 할 수없는 요소를 필터링하므로 사용 시나리오에 따라 하나를 선택합니다.
BrainSlugs83 2014 년

1
@EAGER_STUDENT 실제로 작동 할 수있는 Java를 지나치지 않을 것입니다 (이 모든 우스꽝스러운 유형 삭제 비즈니스, 시도해야합니다 ...).하지만 아니요, 그런 코드를 작성하지 않을 것입니다. 유형 안전성, 컬렉션의 한 요소가 instanceof고객 이 아닌 경우 어떻게됩니까 ?
BrainSlugs83 2014 년

1
@ BrainSlugs83 질문을 한 사람이 캐스팅에 대해 구체적으로 물었습니다. 그리고 Java에 참조하는 .NET 메서드와 같은 관련 메서드가 아직없는 경우 (여전히 btw를 변환하지 않음) 쉽게 추가 할 수 있습니다. 이것은 특정 구문에 대해 묻는 질문과 거의 직교합니다.
Lasse V. Karlsen 2014 년

35

다른 코드에 따라 가장 좋은 답변이 다를 수 있습니다. 시험:

List<? extends Object> list = getList();
return (List<Customer>) list;

또는

List list = getList();
return (List<Customer>) list;

그러나 이러한 확인되지 않은 캐스트를 수행하는 것은 권장되지 않습니다.


3
-1-이것은 들어가기에 정말 나쁜 습관입니다. "Unchecked"주석을 사용하지 않는 한 컴파일러는 여전히 그것에 대해 불평 할 것입니다
kdgregory

24

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());

1
그래도 캐스트 라기보다는 카피에 가깝습니다.
200_success

수락 된 답변에 언급 된 캐스팅이 저에게 효과적이지 않았습니다. 또한 저는 Java 7을 사용 FluentIterable했습니다 .하지만 Guava가 저를 위해 일했습니다.
Sridhar Sarnobat

이것은 내가 찾고 있었던 것입니다, 난 그냥 구문을 몰랐다
커피에 힘 입어

23

이중 캐스트를 사용할 수 있습니다.

return (List<Customer>) (List) getList();

8

저는 자바 프로그래머가 아니지만 .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도 마찬가지입니다.

나보다 더 나은 자바 지식을 가진 사람이 자바 미래 또는 구현에 대한 세부 사항을 알려줄 수 있기를 바랍니다.


3
Java의 미래는 ... Scala입니다. 진지하게, 제네릭을 Java에 추가 한 사람은 Java와 모호하게 유사하지만 실제로 유형에 능숙한 새로운 언어를 개발했습니다. 매우 철저하고 일관된 유형 처리 구현입니다. 어떤 Scala 기능이 언제 Java로 돌아갈 지 아무도 모른다고 생각합니다.
Carl Smotricz 2009

OP 질문에 진정으로 답하는 공분산에 대한 훌륭한 설명입니다. 잘 했어.
Kevin Day

Carl : 일부 Java 개발자가 C #을 만들려고했다고 생각 했습니까? :) 어쨌든 예, Java는 덜 강력한 유형의 것 대신 미래에 Scala의 방향으로 갈 가능성이 큽니다.
Esko

@Carl-Scala에서는 기본적으로 목록이 변경 불가능하다는 점에서 미묘한 차이가 있습니다. 따라서 일반적으로 고객 목록에 개체를 추가하는 데 문제가 없습니다. 이렇게하면 개체 목록 이 표시되기 때문 입니다.
Brian Agnew

어 ... 기술적으로 이것은 정확하지만 .NET 4.0 이전에도 일반 IEnumerable 확장 메서드 (.Cast <> 및 .OfType <>)를 사용하여이 작업을 수행 할 수 있으므로 다음과 같은 경우 깊은 끝을 벗어날 필요가 없습니다. 강력한 유형 반복을 원합니다.
BrainSlugs83 2014 년

7

또 다른 접근 방식은 Java 8 스트림을 사용하는 것입니다.

    List<Customer> customer = myObjects.stream()
                                  .filter(Customer.class::isInstance)
                                  .map(Customer.class::cast)
                                  .collect(toList());

1
감사합니다.이 솔루션은 메서드 참조를 사용하여 매우 아름답습니다
thang

1
누군가가 그렇게 아래로 스크롤 할 것이라고는 생각하지
못했습니다

3

목록을 반복하고 모든 오브젝트를 하나씩 캐스트해야합니다.


3

다음과 같이 할 수 있습니다.

List<Customer> cusList = new ArrayList<Customer>();

for(Object o: list){        
    cusList.add((Customer)o);        
}

return cusList; 

또는 자바 8 방식

list.stream().forEach(x->cusList.add((Customer)x))

return cuslist;

2

당신 때문이 아니라 수 List<Object>List<Customer>같은 상속 트리에 있지 않습니다.

List<Customer>a List<Object>를 사용 하는 클래스에 새 생성자를 추가 한 다음 각각 Object을 a로 캐스팅 Customer하고 컬렉션에 추가 하는 목록을 반복 할 수 있습니다. 호출자가 List<Object>.NET Framework가 아닌 무언가를 포함 하는 경우 잘못된 캐스트 예외가 발생할 수 있습니다 Customer.

일반 목록의 요점은 특정 유형으로 제한하는 것입니다. 주문, 제품 등 무엇이든 포함 할 수 있는 목록을 가져 와서 고객 만 가져올 수있는 목록으로 압축하려고합니다.


2

새 목록을 만들고 여기에 요소를 추가 할 수 있습니다.

예를 들면 :

List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);

1

가장 좋은 방법은 새 List<Customer>를 만들고을 반복 List<Object>하고 새 목록에 각 항목을 추가 한 다음 반환하는 것입니다.


1

다른 사람들이 지적했듯이 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.
  }
});

1

위의 Bozho와 비슷합니다. 이 방법을 통해 (내 자신이 마음에 들지 않지만) 여기에서 몇 가지 해결 방법을 수행 할 수 있습니다.

public <T> List<T> convert(List list, T t){
    return list;
}

예. 목록을 요구되는 일반 유형으로 캐스팅합니다.

위의 경우 다음과 같은 코드를 수행 할 수 있습니다.

    List<Object> list = getList();
    return convert(list, new Customer());

이 솔루션이 마음에 듭니다. SuppressWarnings를 추가해야하는 경우에도 안전하지 않은 모든 캐스팅보다 한 곳에 추가하는 것이 좋습니다.
robson

1

목록으로 수행하려는 작업에 따라 목록을 List<Customer> . Customer목록 에 개체 만 추가하려는 경우 다음과 같이 선언 할 수 있습니다.

...
List<Object> list = getList();
return (List<? super Customer>) list;

이것은 합법적입니다 (글쎄요, 합법적 일뿐만 아니라 정확합니다 -목록은 "고객에게 일부 상위 유형"입니다). 목록에 객체를 추가하는 메서드에 전달하려는 경우 위의 제네릭 경계면 충분합니다.

반면에 목록에서 개체를 검색하고이를 Customers로 강력하게 입력하려면 운이 좋지 않은 것입니다. 목록은List<Object> 콘텐츠가 고객이라는 보장이 없으므로 검색시 자신의 캐스팅을 제공해야합니다. (또는 목록 Customers에 다른 답변 중 하나의 이중 캐스트 만 포함 하고 사용 한다는 것을 정말로, 절대적으로 두 배로 확신하십시오. 케이스).

광범위하게 말하면 메서드를 작성할 때 허용되는 가능한 가장 광범위한 제네릭 경계를 고려하는 것이 좋습니다. 라이브러리 메서드로 사용되는 경우 두 배입니다. 예를 들어 목록에서만 읽을 경우 List<? extends T>대신을 사용 List<T>하십시오. 이렇게하면 호출자에게 전달할 수있는 인수의 범위가 훨씬 더 넓어 지고 사용자 와 유사한 문제가 발생할 가능성이 적습니다. 여기에 다시 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.