Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java static members in a subclass accessed via a generic parent

This seems like a newbish question, but the last time I worked with Java, the language didn't have generics. I have a class hierarchy (names changed to be as generalized as possible):

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

I'm trying to clean up some legacy code, and there's one place where a ton of repetitive duplication can all be factored out into a single routine via generics. (I'm thinking generics because when this routine is called, it needs to operate on only one of the concrete classes.)

The routine looks like

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

I'm leaving out about a zillion lines, but that's the important part: someFunc() is type parametric (it actually takes arguments but none of them are Things so no inference). Eventually I need to fetch a special token and this is where I'm getting fuzzy.

The tokens are huge-ass unique strings for each concrete class. They're class-based, not instance-based. The actual token value is declared as a private static final field in each subclass.

So I need to use the public methods/fields of a base class to (eventually) get to the private static field of a subclass. Obviously I can't declare an abstract static method in the base, because that makes no sense. If the data were instance-based, then this would be trivial, with a polymorphic getter in the base class, but the subclass stuff is static.

I feel like I'm missing a feature of Java generics here, but I can't use Thing.whatever() unless the whatever is something that's possible to declare in the abstract base class. I'm running up against either limitations of Java or my lack of expertise trying to bridge the gap. The one attempt I made that seemed promising also had a ton of code duplication all the way down the class hierarchy, defining abstract methods with the exact same code over and over... which is what generics are supposed to help prevent!

like image 458
Ti Strga Avatar asked Nov 27 '12 16:11

Ti Strga


2 Answers

I'm running up against either limitations of Java or my lack of expertise trying to bridge the gap.

It's a limitation of Java, although a fairly reasonable one IMO. Basically you're still trying to use static members as if they were polymorphic, and that's not going to work - generics don't help you there.

Options:

  • Use reflection... but bear in mind that type erasure means you can't get at the Class for Thing unless you pass it in explicitly
  • If you've got an instance of Thing anyway, just make it an abstract instance member, which in each implementation happens to return the value of a static field
  • Create a separate type hierarchy which will use instance members
like image 112
Jon Skeet Avatar answered Oct 26 '22 06:10

Jon Skeet


If I understand it correctly, you need the concrete class of the type parameter. The usual way of doing it is to declare your method like this: public <T extends AbstractBase> void someFunc(Class<T> clazz)

This of course means an extra parameter needs to be passed to the method and you need to use reflection to access the static fields, but given Java's type erasure it's the only way.

The moral of the story is that generics and statics don't go very well together.

like image 3
biziclop Avatar answered Oct 26 '22 06:10

biziclop