tags:

views:

272

answers:

7

I have an abstract superclass and various subclasses. Each sublcass contains a value that I would like to use statically but it is not possible to create an abstract static method. I want to get a value from them dynamically without having to create instances. What do I do?

Another question would be: How would I loop through subclasses? Is it it even possible?

One attempt involved mapping class names (Subclass.class) to the value and trying to use the newInstance on them so I could use a method to get the value but this doesn't work.

Where am I going wrong in my approach?

+1  A: 

Why not go about it the other way? Put the data someplace statically accessible and have the subclasses get it from there?

Of course, the feasibility of this depends on the nature of the data but when you find yourself hitting this sort of barrier it often helps to step back and reexamine your assumptions.

-- MarkusQ

MarkusQ
You lose some encapsulation with this method but I think that it's probably the way to go in this case.
Outlaw Programmer
A: 

If you have a fixed set of subclasses then you can put the data in the superclass. If you subclasses can be added, then there is no way to list them all. You might get subclasses let the superclass know of their existence from the static initialiser (or use an agent!).

Generally superclasses should not be aware of their subclasses. However you might want to think (or better refactor) your superclass into a supertype and some other class responsible for your subclasses.

Tom Hawtin - tackline
A: 

You will need to to scan package(s) and clasess to find ones that extend your superclass - unfortunately, this cannot be done with the Reflection API, but must be done through URLs (file system classes, jar files etc). Annotation use is probably better in this case, and lots of open source products use this method (Hibernate etc).

Then you can have a static method in each (either consistent naming or annotated) which you should be able to invoke with as method.invoke(MyObject.class, arguments)

The other option is to put a registry map in the abstract class - if you need to mandate it, the abstract constructor takes the static value (or just stores the subclass if calculations are needed). If you're controlling all subclasses, just make sure you have a static block in each one to add it to the registry.

Stephen
If I recall correctly, you cannot scan packages using the reflection API.
McDowell
Thanks - I'd forgotten that..
Stephen
+1  A: 

You can reference static members/methods via reflection, but there is not automatic way to find all subclasses of a class.

Consider providing the subclasses/instance factories/metadata classes via some other mechanism, such as ServiceLoader services or some other plugin framework.

McDowell
+1  A: 

Maybe you are looking for enums?

public enum Planet
{
  MERCURY (2.4397e6),
  VENUS   (6.0518e6),
  EARTH   (6.37814e6);

  private final double radius;

  Planet(double radius)
  {
    this.radius = radius;
  }

  public double radius()
  {
    return radius;
  }
}

You don't have to create enum instances yourself. Enums can have values, e.g. radius() in the example. You can add behaviour to them so they can act like normal classes, by defining abstract methods on them, e.g.

public enum Planet
{
  ...
  abstract double weightOnSurface(double weight);
  ...
}

You can loop through enums, like this:

for (Planet p : Planet.values())
{
  System.out.println(p.radius());
}

So they seem to meet all your criteria.

eljenso
A: 

Mapping subclasses... you can do it via reflection (but it won't be fun).

newInstance() (likely) won't work unless:

  • the class is public
  • the constructor is public
  • the constructor takes no arguments

The last one is mandatory, the other two depend on what package you are doing things from (I think, been a while since I cared). Using the Constructor class is better.

Can you give a short code example of what it is you are thinking of doing? Based on that I (and others) might be able to give you better answers. If you do need to do the mapping subclass thing I can dig up some code that does it...

TofuBeer
+1  A: 

Creating a second class for each of your subclasses which represents the type of that subclass might work.

For example, create a factory class for each subclass (a class that is responsible for creating instances of that subclass). There only needs to be one instance of each factory class.

Each factory class can then be responsible for knowing the subclass-specific data you describe. You then just need to loop over a fixed set of factory classes.

Russell Mayor
I used an enum factory.
Improfane