2012-11-27 14 views
9

Bu, yeni bir soru gibi görünüyor, ancak Java ile en son çalıştığımda, dilin jenerik değeri yoktu.Bir jenerik üst öğe aracılığıyla erişilen bir alt sınıftaki Java statik üyeleri

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

Bazı eski kod temizlemeye çalışıyorum ve tekrarlayan mükerrer bir ton tüm içine çarpanlarına olabilir bir yer var: Bir sınıf hiyerarşisi vardır (isimler olabildiğince genelleştirilmiş gibi olacaktır olarak değiştirildi) jenerikler üzerinden tek bir rutin. (Bu rutin çağrıldığında, bu somut sınıfların sadece biri üzerinde işlemesi için ihtiyaç duyduğu çünkü generics düşünüyorum.)

rutin görünüyor

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] 
} 

gibi milyonlarca hatları hakkında bilgi gidiyorum Ancak, önemli olan budur: someFunc(), parametrik tipte (aslında argümanları alır, ancak bunların hiçbiri Nesnelerdir ve hiçbir çıkarım yoktur). Sonunda özel bir jeton almam gerekiyor ve burası bulanıklaşıyorum.

Simgeler her bir beton sınıfı için çok büyük boyutlu benzersiz dizelerdir. Sınıf tabanlı, örnek tabanlı değiller. Asıl jeton değeri, her bir alt sınıfta private static final alanı olarak bildirilir. Bu nedenle bir alt sınıfın genel yöntemlerini/alanlarını (sonunda) bir alt sınıfın özel statik alanına getirmesi için kullanmalıyım. Açıkçası, tabanda bir abstract static yöntemini bildiremiyorum, çünkü bu hiç mantıklı değil. Veriler örnek temelliyse, bu temel sınıfta bir polimorfik getter ile önemsiz olur, ancak alt sınıf şeyler statiktir.

Burada bir Java jenerik özelliği yok gibi hissediyorum, ancak whatever soyut temel sınıfında bildirmek mümkün olan bir şey olmadıkça Thing.whatever() kullanamazsınız. Java'nın kısıtlamalarına ya da boşluğu kapatmaya çalışan uzmanlık eksikliğime karşı koşuyorum. Benim vaat ettiğim bir girişimi de, sınıf hiyerarşisinin sonuna kadar bir kod çoğaltması vardı, soyut kodları tam olarak aynı kodla tanımladı.

+2

+1 ZZ9PluralZAlpha' :-) –

cevap

7

Java'nın kısıtlamalarına veya boşluğu kapatmaya çalışan uzmanlık eksikliğime karşı koşuyorum.

Her ne kadar oldukça makul bir IMO olsa da, Java'nın bir sınırlamasıdır. Temel olarak statik üyeleri hala polimorfikmiş gibi kullanmaya çalışıyorsunuz ve bu işe yaramayacak - jenerikler size orada yardımcı olmuyor.

Seçenekler:

  • o tip silme Eğer var bıraktıysanız açıkça
  • bunu geçmesi sürece Thing için Class almak anlamına gelir akılda Kullanım yansıması ... ama ayı zaten Thing örneğidir, sadece
  • ayrı tip hierar oluşturun, her uygulamada statik alanın değerini döndürmek olur soyut örneği üyesi yapmak Eğer olduğu gibi, bir private static final alan belirteci tutmak istiyorsanız örnek üyelere
3

Doğru anlıyorsam, tür parametresinin somut sınıfına ihtiyacınız vardır. Bunu yapmak için her zamanki yöntem, yönteminizi şu şekilde bildirmektir: public <T extends AbstractBase> void someFunc(Class<T> clazz)

Bu, yönteme aktarılacak ek bir parametrenin olması gerektiği anlamına gelir ve statik alanlara erişmek için yansıma kullanmanız gerekir, ancak Java'nın tip silme işlemi uygulanmışsa tek yol bu.

Hikayenin ahlakı, jenerik ve statiğin birlikte pek iyi gitmemesidir.

2

Biraz aksak ama eğer someFunc Yansıma kullanabileceği bir Class<Thing> parametre aldı:

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

Ama belki

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"; } 
    } 
} 

ve benzeri bir şey iç içe sınıfları kullanarak polimorfizm daha iyi yararlanmak someFunc, AbstractBase.Info parametresini al.

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

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

fikri hiyerarşisindeki her sınıfInfo ait onun eskiden-statik verileri tutan bir tekil örneğini sahip olmasıdır.

+0

Bu sorun; zaman zaman bazıFunc denir, hiçbir şey geçmez. Ama yansıma başka bir bakacağım, bu yüzden teşekkür ederim! –

+0

@TiStrga Verileri alternatif bir yaklaşım üzerinde genişlettik ve verileri doğrudan statikten ziyade başka bir sınıfın tek bir örneğine yerleştirdim. –

1

kullanacak chy, sen yansıma yoluyla alabilirsiniz: Çağrı sitesinde

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

, sen someFunc(ConcreateSubZZ9PluralZAlpha.class) yapmak zorunda . Ama bunu yapabilirsen, neden token nesnesini someFunc(ConcreateSubZZ9PluralZAlpha.concreteSpecialToken)'daki gibi bir parametre olarak geçirmiyorsun? Veya belki de someFunc() yöntemini simge sınıfının kendisine taşıyın.

İlgili konular