通过通用父级访问的子类中的Java静态成员

时间:2012-11-27 16:25:27

标签: java generics static abstract

这似乎是一个新的问题,但上次我使用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的局限或者我缺乏专业知识来弥补差距。我所做的一次尝试似乎很有希望在类层次结构中一直有大量的代码重复,一遍又一遍地用完全相同的代码定义抽象方法......这是泛型应该有助于防止的东西!

4 个答案:

答案 0 :(得分:7)

  

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

这是Java的一个限制,虽然是一个相当合理的IMO。基本上你仍然试图使用静态成员,就好像它们是多态的一样,并且这样做不会起作用 - 泛型对你没有帮助。

选项:

  • 使用反射...但请记住,类型删除意味着除非您明确传递,否则您无法访问Class Thing
  • 如果你 得到了Thing的实例,只需将其设为一个抽象的实例成员,在每个实现中都会返回值静态字段
  • 创建一个单独的类型层次结构,它将使用实例成员

答案 1 :(得分:3)

如果我理解正确,你需要type参数的具体类。通常的方法是声明您的方法:public <T extends AbstractBase> void someFunc(Class<T> clazz)

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

故事的寓意是仿制药和静力学并不是很好。

答案 2 :(得分: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的单个实例,其中包含以前的静态数据。

答案 3 :(得分:1)

如果你想保留令牌,private static final字段,你可以通过反思得到它:

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()移动到令牌类本身。