2010-12-09 2 views
10

하나의 필드가 다른 필드의 하위 집합이고 상위 집합 클래스의 getter가 모두 예기치 않게 (getFoo())이라는 클래스 쌍이 있습니다. 어떤 방법으로 효율적으로 슈퍼 세트 클래스에서 하위 집합 클래스로 모든 일반적인 필드를 복사하거나 적어도 그렇게하려면 코드를 자동 생성하십시오. 나는 상위 클래스를 편집 할 수 없습니다, 여러 가지 이유로Java의 비슷한 클래스간에 필드 복사

  • 를,도 그냥 데이터 복사를 할 것을 피하기 위해 전반에 걸쳐 사용할 수 있습니다 :

    나는 점에 유의해야한다.

  • 잠재적으로 하위 집합 클래스에서 새 메서드를 만들 수 있지만 필드를 변경할 수는 없습니다.
  • 우리는 이러한 수십 개의 쌍을 가지고 있으며, 일부 클래스는 많은 필드가 있으므로 일부러 손으로 직접하는 것은 다루기가 쉽지 않습니다.
  • 동료는 자바 리플렉션을 사용하여 두 클래스를 가져 와서 필드를 문자열로 반복하고 문자열 조작을 통해 getter 이름을 확인한 다음 자동 실행되도록 일반 복사 방법을 만드는 방법을 고안했습니다 부분 집합 클래스의 필드 그것은 끔찍하지만 작동하는 것 같습니다. 더 좋은 방법이 있기를 정말로 바라고 있습니다.

편집 : 요청

public class SuperClass { 
    private int foo; 
    private int bar; 
    private float bat; 
    public int getFoo() { return foo; } 
    public int getBar() { return bar; } 
    public float getBat() { return bat; } 
} 

public class SubClass { 
    private int foo; 
    private float bat; 
} 

//wanted 
public static copySuperFieldsToSubMethod(Object super, Object sub) { ??? } 

// also acceptable would be some way to autogenerate all the assignment 
// functions needed 
+0

수퍼 세트 클래스를 편집 할 수 있다면 간단히 서브 세트 클래스를 확장하고 클래식 OO 방식으로 모든 필드와 메소드를 상속 할 수 있습니다. 왜 수퍼 클래스를 편집 할 수 없습니까? – Asaph

+0

@Asaph - 슬프게도, 수퍼 셋 클래스는 개별적으로 개발 된 외부 라이브러리의 일부이며 이제는 더 큰 클래스의 정보를 많이 활용하지 않는이 특정 프로젝트 용 클래스로 변환 할 수 있어야합니다. . – Dusty

+0

관계를 뒤집어서 하위 집합 클래스가 수퍼 클래스에서 상속 된 경우 어떻게해야합니까? 빈 몸체가 필요하지 않은 필드와 관련된 모든 메서드를 재정의 할 수 있습니다. 너무 우아한 것은 아니지만 적어도 복사/붙여 넣기, 반사 또는 코드 생성없이 코드를 다시 사용할 수 있습니다. – Asaph

답변

12

과 같은 몇 가지 간단한 코드는이 작업을 수행하는 스프링 프레임 워크의 BeanUtils 클래스를 사용할 수 있습니다. 리플렉션 기반 기법보다 더 효율적 일 필요는 없지만 코드 작성은 확실히 간단합니다. 나는 당신이 할 필요가 모든 것을 기대 : 그 적합하지 않는 경우이 방법

BeanUtils.copyProperties(source, target); 

자바 독은 또한 스프링 프레임 워크에 BeanWrapper/BeanWrapperImpl 사용을 고려할 수 http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)

에서 확인할 수있다 클래스의 속성을 반복합니다. 저수준의 리플렉션 API를 사용하는 것보다 간단합니다.

+1

와우, 그건 본질적으로 내가 찾고있는 것이지만,이 문제에 대한 스프링 프레임 워크를 작성하는 것이 타당하지 않을 것이라고 생각합니다. – Dusty

+4

Apache Commons BeanUtils가 적합 할 수도 있습니다. Spring보다 약간 가볍습니다. 그것은 똑같은 이름의 클래스와 메소드를 가지고 있습니다. http://commons.apache.org/beanutils/ – gutch

+0

을 참조하십시오. Spring 버전은 상속을 통해 관련된 클래스에서 더 잘 작동합니다. – raffian

0

게시물에서 언급 한 시나리오를 묘사하는 앱의 샘플 코드를 제공 할 수 있습니까? 지금 리플렉션은 런타임시 클래스 멤버를 검사 할 수 있으므로 가장 좋은 방법입니다.

+0

몇 가지 예제 코드를 추가했지만 일반 코드 (실제 코드를 표시 할 수 없음) – Dusty

+0

@ gutch의 접근 방식은 요구 사항에 정확하게 부합하지만 불행히도 사용할 수 없습니다. –

2

런타임 성능면에서 효율적으로 작업을 수행하려면 getters 및 setters를 사용하여 복사본을 손으로 코딩하는 것이 좋습니다. getter 또는 setter 메서드에 대해 펑키 한 것이 없으면 해당 필드의 본문이 인라인되어 필드 배정을하는 것만 큼 빠릅니다.

반사 방식 (예 : BeanUtils과 같은 기존 클래스 사용)은 코딩이 적지 만 getter 및 setter를 간단한 방법으로 호출하는 것보다 느린 순서 일 수 있습니다. 자신을 구현하려고하면, 특히 반사 복사 클래스/메소드가 오버로드 된 메소드, 상속, 값 변환, boxing/unboxing 등을 처리해야하는 경우에 대비하여보다 많은 작업을 할 수 있습니다.

코드 생성 방식을 사용하면 복사 기술을 직접 작성하는 것보다 코드 생성 (원하는 기술을 사용하여 선택)을 구현하는 데 드는 노력과 복잡성을 균형있게 조정해야합니다. 아마도 20 클래스 이전에 코드 생성 방법을 사용해도 아마 깨지 않을 것입니다 ...기술에 익숙하지 않은 사용자는 더 많은 정보를 얻을 수 있습니다.

1

하위 집합 필드를 상위 집합의 일반 필드로 채울 수있는 클래스의 소스 코드를 자동 생성하기위한 간단한 Java 도구를 작성했습니다. 이 도구는 리플렉션을 사용하여 getter 및 setter 메소드의 이름을 가져옵니다. 나머지는 메모리에 소스 파일을 "쓰고"*.java 파일에 저장하는 (사소한) 문자열 작업입니다. 이 모든 자동 생성 파일을 컴파일하고 클래스 파일을 클래스 경로에 추가하십시오.

클래스는 다음과 같이 수 있습니다 : 첫 번째 대답 유사

class AClassToBClassPopulator implements Populator { 
    @Overwrite 
    public void populate(Object superSet, Object subSet) { 
     subSet.setFieldA(superSet.getFieldA()); 
     subSet.setFieldB(superSet.getFieldB()); 
     // .. and so on. The method body is created through reflection 
    } 
} 
0

다른 사람이 이미 유효한 제안하면서 어쩌면, 여기에 약간의 헤비급 솔루션 비록이 분명히 자바의 반사를위한 작업이며 하나 더 :

약 1 년 전 나는 BeanPropertyController이라는 작은 JavaBean 속성 수정 자 라이브러리를 작성했습니다. 누구에게도 특별히 권하지는 않지만, 도서관의 이름을 지은 클래스 (see source)는 귀하의 요구에 유사한 기능을 채택하기위한 참조 자료로 사용될 수 있다고 생각합니다. 간단한 예를 들어, 여기에 (거의 !) 내가 할 BPC를 사용하는 방법은 당신이 요구하는지 :

// somewhere in code... 
SuperClass a = new SuperClass(); 
a.foo = 101; 
a.bar = 102; 
a.bat = 103f; 

SubClass b = new SubClass(); 
b.foo = 201; 
b.bat = 202f; 

BeanPropertyController fromB = BeanPropertyController.of(b, ExtractionDepth.QUESTIMATE); 
BeanPropertyController toA = BeanPropertyController.of(a, ExtractionDepth.QUESTIMATE); 

// This is where the magic happens: 
for (String propertyName : fromB.getPropertyNames()) { 
    toA.mutate(propertyName, fromB.access(propertyName)); 
} 
a = (SuperClass) toA.getObject(); 
b = (SubClass) fromB.getObject(); 

System.out.println("SuperClass' foo="+a.foo+" bar="+a.bar+" bat="+a.bat); 
System.out.println("SubClass' foo="+b.foo+" bat="+b.bat); 

이, 그래서

SuperClass' foo=201 bar=102 bat=202.0 
SubClass' foo=201 bat=202.0 

출력합니다 제가 제안하는 것은 당신이 갈 것입니다 URL에 연결하여이 코드를 필요에 맞게 수정하십시오. 나는 당신이 포함 시켰던 다양한 인스턴스화 메소드, 디폴트 값 제공자 등을 필요로하지 않는다고 확신한다. 그리고 예, BPC는 더 이상 사용되지 않는 것으로 간주 될 수 있습니다.

관련 문제