2014-10-30 2 views
4

한다고 가정 우리가 다음 것은 우리가 cloneList를 원하는 것입니다자바 목록 <Parent> 및 목록 <Children> 방법

public List<Something> cloneList(List<Something> original){ 
    List<Something> newList=new ArrayList<>(); 
    for(Something e:original){ 
     Something newE=new Something(); 
     newE.setXXX(e.getXXX()); 
     newList.add(newE); 
    } 
    return newList; 
} 

:

public class Parent{ 
    public void setXXX(String XXX); 
    public String getXXX(); 
} 

public class Children extends Parent{ 
.... 
} 

지금 나는 다음과 같은 방법이라고 복제 목록을 만들려면 List<Parent>List<Children> 모두에 적용 할 수 있습니다. 따라서 어쨌든 "Something"에 적용 할 수 있습니까? 1. 어떤 직렬화 방식이나 반사를 사용하지 마십시오

뭔가? "부모를 확장"또는 인해 Collection<Children>

가정에 호환되지 않는 자바 Collection<Parent>에 "부모"가 될 수 없습니다.

  1. 우리는 Parent and Children 클래스를 수정할 수 없습니다. 이것은 타사 Jar에서 미리 정의됩니다. 적어도에 대한, 그리고

    public <X extends Parent> List<X> cloneList(final List<X> original) 
    

    가 작동합니다 2.

+1

< >을 괄호 안에 게시 할 수 없다는 사실을 고려하십시오. 질문을 코드로 지정하지 않으면 –

+0

제네릭 사용 ... – brso05

+1

추가 한 모든 제약 조건을 만족하는 솔루션이 없습니다. 클래스가 정적으로 알려지지 않은 개체의 충실한 복사본을 만들려면 정적 또는 사용 가능한 것으로 알려진 메서드를 사용해야합니다. 이러한 클래스에서 복사 메서드를 이미 사용할 수 있으면 확실하게 샘플 코드에서 복사 메서드를 사용하게됩니다. (Object.clone()은 그 목적을 달성 할 수 있지만 부모 클래스가 Cloneable을 구현할 때만 가능하다. 그렇다고하더라도 Object.clone()은 매우 문제가 될 수있다.) –

답변

0

변경 cloneList의 서명에 명시된대로 우리가 부모를 수정할 수 없기 때문에

  • SuperParent 클래스는 불가능합니다 메소드 서명. 내부적으로 List<Parent>을 생성 한 다음 List<X>으로 전송하고 필요한 경우 경고를 무시하십시오. 런타임 유형 "X"를 찾을 방법이 없습니다.

  • 1

    제네릭을 이러한 방식으로 사용할 수 없으며 리플렉션 만 사용할 수 있습니다.

    변수 유형이 T 인 경우 new T()을 사용할 수 없습니다. 왜냐하면 제네릭은 컴파일 타임 메커니즘이기 때문에 런타임에 new이 특정 유형의 객체를 만드는 데 사용되며 컴파일러는 컴파일 타임에 해당 유형에 대한 적절한 참조를 만들 수 없기 때문입니다. 컴파일러는 실제로 원시 ArrayList 유형을 만들기위한 코드로 컴파일하기 때문에

    new ArrayList<T>(); 
    

    ,이 법적 :이 동안 그래서 컴파일러가 알지도하지 않기 때문에,

    new T(); 
    

    이 아닌 것 실제 클래스는 (심지어 T extends Parents으로 정의 되었더라도 Grandchildren 같은 프로그램을 컴파일 할 때 작성되지 않은 클래스 일 수도 있으며 매개 변수없는 생성자가 있는지조차 알지 못합니다.

    2

    자바에서는 불가능합니다. Generic syntax for extends or equal to을보십시오.

    다음과 같이 메소드를 변경하고 상위 클래스를 슈퍼 부모로 확장 할 수 있습니다.

    public static <T extends SuperParent> List<T> cloneList(List<T> original, Class<T> type) throws IllegalAccessException, InstantiationException { 
        List<T> newList=new ArrayList<>(); 
        for(T e : original){ 
         T x = type.newInstance(); 
         x.setXXX(e.getXXX()); 
         newList.add(x); 
        } 
        return newList; 
    } 
    

    또한 다른 복제 방법을 선택할 수도 있습니다.예를 들어, 'SerializationUtils을 아파치 코 몬즈를 사용 : 그러나, 당신의 가장 큰 문제입니다

    public <T extends Parent> List<T> cloneList(List<T> original) 
    

    :

    List<Children> result = (List<Children>) SerializationUtils.clone(originalList); 
    
    +1

    나는 직렬화에 대한 조언 (또는 두려운 '복제본'에 대해 더 많이 동의하지만, 방금 언급 한 것을 잊어 버리십시오)은 반사 기반 제안보다 더 큽니다. 먼저 매개 변수없는 생성자가 있다고 가정합니다. 둘째, 새로운 복사본은 올바른 형식을 갖지만 원본의 전체 내부 상태를 갖지 않으므로 직렬화가 선호됩니다. – RealSkeptic

    0

    을 일반적인 의미에서,이 서명을 갖는 방법을 사용할 수 있어야합니다. 그 목록 요소의 복사본을 얻는 것입니다. 귀하의 코드는 사용할 수 없습니다

    형식 인수 T에 대한 무효 생성자의 존재를 보장 할 수 없기 때문에 코드를 사용할 수 없습니다. 대신 올바르게 형식이 지정된 복사본을 반환하는 메서드가 필요합니다. 완전한 유형 안전으로는이 작업을 수행 할 수 없지만 가까이 올 수 있습니다. 과 같이 당신의 방법을 쓰기 다음

    public Parent Parent.copy(); 
    public Children Children.copy(); 
    

    ... 방법이 적절한 무엇에, 그리고 : 당신은이 방법을 구현할 수

    public <T extends Parent> List<T> cloneList(List<T> original) { 
        List<T> newList = new ArrayList<>(); 
    
        for (T originalItem : original) { 
         newList.add(original.getClass().cast(original.copy())); 
        } 
    
        return newList; 
    } 
    

    (주 Object.getClass()의 문서화 된 반환 형식이 Class<?> 있지만 그, 이 목적을 위해 작동하지 않는 method documentation은 실제로 반환 유형이 그보다 조금 더 구체적이므로이 작업을 수행 할 수 있다고 말합니다.

    +0

    'new T();'는 nullary 생성자뿐만 아니라 유형 변수를 인스턴스화 할 수 없기 때문에 사용할 수 없습니다. 그러나 더 중요한 것은'copy()'메소드는 클래스에 최종 필드가있는 경우 내부 상태를 올바르게 복사 할 수 없다는 것입니다. 복사 생성자가 필요할 것이고,이 경우에는 getConstructor (...)를 사용해야 할 것이다. – RealSkeptic

    +0

    @RealSkeptic 내가 제안한'copy()'메소드는 하나의 객체에서 다른 객체로 상태를 복사하지 않고, 호출 된 객체의 복사본을 리턴합니다. 그것은 복사 생성자 (copy constructor)를 호출하는 것을 포함하여, 그것이 할 필요가있는 어떤 방법으로도 할 수 있습니다. 객체 클래스의 인스턴스 메소드이기 때문에 리플렉션을 사용할 필요가 없으므로 어떤 생성자를 사용해야하는지, 클래스의 객체를 인스턴스화하는 방법을 알고 있습니다. –