2010-12-09 17 views
10

我有一對類,其中一個字段是另一個字段的子集,超集類的getter都是可預測命名的(getFoo())。有沒有辦法有效地將超集類的所有常用字段複製到子集類,或者至少自動生成代碼來執行此操作。在java中類似類之間的複製字段

我應該注意的是:

  • 由於種種原因,我不能編輯超類,我也可以只使用它們整個以避免做數據複製。
  • 我可以在子集類中創建新方法,但我無法更改它們的字段。
  • 我們有幾十個這樣的對,有些類有很多很多的領域,所以這樣做是很笨拙至少可以說。
  • 一位同事想出了一種創建通用複製方法的方法,該方法使用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 2010-12-09 05:04:02

+0

@Asaph - 可悲的是,超集類是外部庫的一部分,它是單獨開發的,我現在需要能夠轉換爲爲特定項目創建的類,這些類不利用大型信息中的大部分信息。 – Dusty 2010-12-09 05:08:05

+0

如果將關係顛倒過來並使子集類繼承自超集類,該怎麼辦?您可以覆蓋任何與空身不需要的字段有關的方法。它不是太優雅,但至少你可以在不復制/粘貼,反射或代碼生成的情況下重新使用代碼。 – Asaph 2010-12-09 05:16:17

回答

12

您可以使用BeanUtils類Spring框架來做到這一點。它可能不一定比您的基於反射的技術更有效,但編碼確實很簡單。我希望所有你需要做的是:

BeanUtils.copyProperties(source, target); 

的Javadoc此方法可在http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)

如果不適合,你也可以考慮在Spring框架使用BeanWrapper/BeanWrapperImpl遍歷你的類的屬性。這比使用低級反射API更簡單。

0

您能否提供一些示例代碼來描述您在帖子中提到的場景? 現在反射似乎是最好的方式,因爲它可以讓你在運行時檢查類成員。

2

如果您想要有效地執行任務(就運行時性能而言),那麼使用getters和setters手動編寫副本是一種可行的方法。除非有關吸氣或吸氣方法的東西有些奇怪,否則他們的身體將被內聯,因此它們可以像做場分配一樣快。

反射方法(例如,使用類似BeanUtils的現有類)編碼較少,但可能比以簡單的方式調用getter和setter慢一個數量級。如果你試圖自己實現這一點,你可能會發現自己比你討價還價更多的工作,特別是如果你的反射拷貝類/方法必須處理重載方法,繼承,值轉換,裝箱/拆箱等等。

使用代碼生成方法,您需要平衡實現代碼生成(使用您選擇的任何技術)的努力和複雜性與手動編寫複製方法的努力之間的平衡。在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

這顯然是對Java的反射任務,雖然其他人已經提出有效的,儘管也許有點重量級的解決方案,另外還有一個:

大約一年前,我寫了一個小小的JavaBean屬性修改器庫,名爲BeanPropertyController。儘管我沒有特別向任何人推薦它,但我確實認爲庫的同名類(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可以被認爲是不贊成的。