通过泛型父类访问的子类中的Java静态成员

通过泛型父类访问的子类中的Java静态成员,java,generics,static,abstract,Java,Generics,Static,Abstract,这似乎是一个新问题,但上次我使用Java时,该语言没有泛型。我有一个类层次结构(名称更改为尽可能通用): 我正试图清理一些遗留代码,有一个地方可以通过泛型将大量重复的代码分解成一个例程。(我考虑泛型,因为当调用这个例程时,它只需要对一个具体类进行操作。) 常规看起来像 public <Thing extends AbstractBase> void someFunc() { another_function_call (Thing.concreteSpecialToken);

这似乎是一个新问题,但上次我使用Java时,该语言没有泛型。我有一个类层次结构(名称更改为尽可能通用):

我正试图清理一些遗留代码,有一个地方可以通过泛型将大量重复的代码分解成一个例程。(我考虑泛型,因为当调用这个例程时,它只需要对一个具体类进行操作。)

常规看起来像

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]
}
public void someFunc()
{
另一个函数调用(Thing.concreteSpecialToken);
//也可能是
//另一个函数调用(Thing.concreteSpecialToken());
//如果方法比字段更可行
//不能使用
//另一个函数调用(Thing().concreteSpecialToken());
//因为创建这些类型的实例是一项主要操作[tm]
}
我省略了无数行,但这是重要的部分:
someFunc()
是类型参数化的(它实际上需要参数,但没有参数,所以没有推理)。最后我需要取一个特殊的代币,这就是我变得模糊的地方

标记是每个具体类的唯一字符串。它们是基于类的,而不是基于实例的。实际令牌值在每个子类中声明为
私有静态final
字段

因此,我需要使用基类的公共方法/字段来(最终)访问子类的私有静态字段。显然,我不能在基中声明
抽象静态
方法,因为这毫无意义。如果数据是基于实例的,那么这将是微不足道的,基类中有一个多态getter,但子类是静态的


我觉得这里缺少了Java泛型的一个特性,但是我不能使用
Thing.which()
,除非
which
可以在抽象基类中声明。我遇到了Java的局限性,或者我缺乏专业知识来弥补这一差距。我所做的一次似乎很有希望的尝试在类层次结构中也有大量的代码重复,一次又一次地用完全相同的代码定义抽象方法。。。这就是泛型药物应该帮助预防的

如果我理解正确,您需要类型参数的具体类。通常的方法是这样声明您的方法:
public void someFunc(Class clazz)

这当然意味着需要向该方法传递一个额外的参数,并且需要使用反射来访问静态字段,但是考虑到Java的类型擦除,这是唯一的方法


这个故事的寓意是泛型和静态不能很好地结合在一起。

有点笨拙,但如果
someFunc
采用
参数,则可以使用反射:

public <Thing extends AbstractBase> void someFunc(Class<Thing> clz) {
  // exception handling omitted
  Object whatever = clz.getDeclaredMethod("whatever").invoke(null);
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
获取
AbstractBase.Info
参数

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

// call it as
ConcreteSubB csb = someFunc(ConcreteSubB.INFO);
publicsomefunc(AbstractBase.Info-inf){
String info=inf.getInfo();
}
//称之为
ConcreteSubB csb=someFunc(ConcreteSubB.INFO);
其思想是层次结构中的每个类都有一个
Info
的单例实例来保存其以前的静态数据

我遇到了Java的局限性,或者我缺乏专业知识来弥补这一差距

这是Java的一个限制,虽然在我看来是相当合理的。基本上,您仍然试图使用静态成员,就好像它们是多态的一样,这是行不通的——泛型在这方面帮不了您

选项:

  • 使用反射。。。但是请记住,类型擦除意味着除非您显式地传递它,否则无法获取
    对象的
  • 如果您有一个
    Thing
    的实例,只需将其设置为抽象实例成员,在每个实现中,它恰好返回一个静态字段的值
  • 创建将使用实例成员的单独类型层次结构

如果您想保持令牌的原样,一个
私有静态final
字段,您可以通过反射获得它:

public <Thing extends AbstractBase> void someFunc(Class<Thing> clz) {
  // exception handling omitted
  Object whatever = clz.getDeclaredMethod("whatever").invoke(null);
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);
    }
}
public void someFunc(类clz)
{
试一试{
Field=clz.getField(“concreteSpecialToken”);
字段。setAccessible(true);
Object-concreteSpecialToken=field.get(null);
另一个函数调用(concreteSpecialToken);
}捕获(非法访问例外e){
手柄(e);
}捕获(无此字段例外){
手柄(e);
}
}

在调用站点,您必须执行
someFunc(ConcreateSubZZ9PluralZAlpha.class)
。但是我想知道您是否可以这样做,为什么不将令牌对象作为参数传递,就像在
someFunc(ConcreateSubZZ9PluralZAlpha.concreteSpecialToken)
中一样?或者甚至可以将方法
someFunc()
移动到令牌类本身。

+1对于
ZZ9PluralZAlpha
:-)这就是问题所在;在调用someFunc时,还没有任何东西可以传递。但我会再看一眼反射,谢谢@TiStrga我对另一种方法做了一些扩展,将数据放在另一个类的单例实例中,而不是直接作为静态。