4

Is there a way to instantiate all children of an abstract class dynamically?

What I have currently is similar to this:

public class CommandHandler {

    private Command info        = new Info();
    private Command prefix      = new Prefix();
    private Command roll        = new Roll();
    private Command coin        = new Coin();
    private Command invite      = new Invite();
    private Command quit        = new Quit();
    private Command restart     = new Restart();

}

With the abstract parent class being something like this:

public abstract class Command {

    protected String name;
    protected String arguments;

    protected abstract void execute();

}

But what if I want to instantiate all classes that extend Command without typing them all out individually and adding to the list every time I add a command?

And if I can instantiate them dynamically, can I also manipulate them dynamically? i.e. add each class to a list once it has been instantiated.

Or is there a better design to use that accomplishes what I want in a simpler way?

EDIT: @Ash's solution works perfectly in an IDE, but not when using a jar. All you have to do to make it work in both is change

classPathList.addAll(ClasspathHelper.forClassLoader());

to

classPathList.addAll(ClasspathHelper.forJavaClassPath());

Hope it helps someone!

  • 2
    What if I create a `Command` subclass myself? How would your `CommandHandler` know about that class? (The answer is: No, you can't know all possible subclasses when writing the code.) If the various subclasses are indeed known in compile time, have you considered using an `enum`? – aioobe Jan 16 '17 at 14:11
  • This might help http://stackoverflow.com/q/492184/4338417 – Shrinivas Shukla Jan 16 '17 at 14:14
  • @aioobe Java has reflection for this kind of problem - it is possible at runtime to figure what other classes are available. – Elemental Jan 16 '17 at 15:56
  • 2
    Why do you need this? – MC Emperor Jan 16 '17 at 15:59
  • @MCEmperor I want to load subclasses of a given class without having to type the code myself, as I want to be able to add new subclasses much more easily and elegantly. Commands are one example, but there are lots of other applications for something like this I think. –  Jan 17 '17 at 11:37

1 Answers1

3

If you use maven (if not, you should :p), add the following dependency :

<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>

Then you can list the class you want with the following code (assuming you have a constructor with no parameters) :

public class Loader {

    public static void main(String[] args) {
        try {
            Set<URL> classPathList = new HashSet<URL>();
            classPathList.addAll(ClasspathHelper.forClassLoader());
            Set<Class<? extends Command>> result = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner()).setUrls(classPathList)).getSubTypesOf(Command.class);

            List<Command> commands = new ArrayList<Command>();

            for (Class<? extends Command> c : result) {
                System.out.println(c.getSimpleName());
                commands.add(c.newInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Ji aSH
  • 3,206
  • 1
  • 10
  • 18
  • That works perfectly! Thanks. I didn't know such a thing existed. Also, for those who don't want to use Maven, you need the following jars for it to work: reflections-0.9.10.jar, javassist-3.19.0-GA.jar, guava-15.0.jar, and annotations-2.0.1.jar. –  Jan 17 '17 at 11:35