2012-11-27 79 views
9

這似乎是一個新問題,但是上次我使用Java時,該語言沒有泛型。我有一個類層次結構(名稱變更爲爲廣義地):通過通用父項訪問子類中的Java靜態成員

public abstract class AbstractBase { .... } 
public class ConcreateSubA extends AbstractBase { .... } 
public class ConcreateSubB extends AbstractBase { .... } 
... 
public class ConcreateSubZZ9PluralZAlpha extends AbstractBase { .... } 
... 

我試圖清理一些遺留代碼,並有一個地方,一噸重複重複的都可以被分解成通過泛型的一個例程。 (我想仿製藥,因爲當這個程序被調用,它需要只在具體類的一個操作。)

例行的樣子

public <Thing extends AbstractBase> void someFunc() 
{ 
    another_function_call (Thing.concreteSpecialToken); 
    // could also be 
    // another_function_call (Thing.concreteSpecialToken()); 
    // if methods are more feasible than fields 

    // Cannot use 
    // another_function_call (Thing().concreteSpecialToken()); 
    // because creating instances of these types is a Major Operation[tm] 
} 

我要離開了,卻有無數的線,但這是重要的部分:someFunc()是類型參數(它實際上需要參數,但它們都不是推理)。最終我需要獲取一個特殊的令牌,這是我變得模糊的地方。

標記是每個具體類的巨大驢獨特的字符串。它們是基於類的,而不是基於實例的。實際標記值在每個子類中聲明爲private static final字段。

所以我需要使用基類的公共方法/字段來(最終)獲取到子類的私有靜態字段。顯然,我不能在基地申報abstract static方法,因爲這沒有意義。如果數據是基於實例的,那麼這將是微不足道的,在基類中有一個多態的getter,但子類的東西是靜態的。

我覺得我在這裏錯過了Java泛型的一個特性,但是我不能使用Thing.whatever(),除非whatever是可以在抽象基類中聲明的東西。我遇到了Java的侷限性或者我缺乏專業知識來彌補這個缺口。我所做的那個看起來很有前途的嘗試在整個類層次結構中一直存在大量的代碼複製,並且使用完全相同的代碼來定義抽象方法......這就是泛型應該有助於防止的問題!

+2

+1爲'ZZ9PluralZAlpha' :-) –

回答

7

我遇到了Java的限制或缺乏專業知識來彌補差距。

這是Java的限制,雖然是一個相當合理的IMO。基本上,你仍然試圖使用靜態成員,就好像它們是多態的,這不起作用 - 泛型不會幫助你。

選項:

  • 使用反射...但是請記住,類型擦除意味着你不能在Class得到Thing,除非你通過它在明確
  • 如果你已經Thing實例反正,只讓它作爲一個抽象的實例成員,這在每個實施恰好返回一個靜態字段的值
  • 創建一個單獨的類型hierar CHY如果你想保持令牌,因爲它是一個private static final場將使用實例成員
3

如果我理解正確,則需要類型參數的具體類。通常的做法是聲明你的方法是這樣的:public <T extends AbstractBase> void someFunc(Class<T> clazz)

這當然意味着一個額外的參數需要傳遞給方法,並且你需要使用反射來訪問靜態字段,但是鑑於Java的類型擦除這是唯一的方法。

這個故事的寓意是仿製藥和靜態藥不能很好地結合在一起。

2

有點笨重,但如果someFunc拿了Class<Thing>參數,你可以使用反射:

public <Thing extends AbstractBase> void someFunc(Class<Thing> clz) { 
    // exception handling omitted 
    Object whatever = clz.getDeclaredMethod("whatever").invoke(null); 

但你也許可以通過使用嵌套類,像

public abstract class AbstractBase { 
    public static class Info { 
    public String getInfo() { 
     return "AbstractBase"; 
    } 
    } 
} 

public class ConcreteSubA extends AbstractBase { 
    public static final Info INFO = new Info() { 
    public String getInfo() { return "ConcreteSubA"; } 
    } 
} 

,並採取多態性更好地利用有someFunc參數AbstractBase.Info

public <Thing extends AbstractBase> someFunc(AbstractBase.Info inf) { 
    String info = inf.getInfo(); 
} 

// call it as 
ConcreteSubB csb = someFunc(ConcreteSubB.INFO); 

的想法是,每個層次結構中有一個單實例Info持有其前身爲靜態數據。

+0

這是麻煩;在someFunc被調用的時候,還沒有任何東西存在。但我會再看看反射,所以謝謝! –

+0

@TiStrga我對另一種方法進行了擴展,將數據放在另一個類的單例實例中,而不是直接作爲靜態方法。 –

1

,你可以得到它通過反射:

public <Thing extends AbstractBase> void someFunc(Class<Thing> clz) 
{ 
    try { 
     Field field = clz.getField("concreteSpecialToken"); 
     field.setAccessible(true); 
     Object concreteSpecialToken = field.get(null); 
     another_function_call (concreteSpecialToken); 
    } catch (IllegalAccessException e) { 
     handle(e); 
    } catch (NoSuchFieldException e) { 
     handle(e); 
    } 
} 

在調用點,你要做的someFunc(ConcreateSubZZ9PluralZAlpha.class) 。但是,我想知道你是否可以這樣做,爲什麼不只是將令牌對象作爲參數傳遞,如someFunc(ConcreateSubZZ9PluralZAlpha.concreteSpecialToken)?或者甚至可能將方法someFunc()移動到令牌類本身。