0

Here is what I would like to do:

Say I created a class called Animal. Then I create a class called Dog that extends Animal. With only doing that, is it possible to add Dog to a list in a 3rd class called AnimalManager? It's fine if I have to call a method in the Animal class, but I want an instance of Dog to be created without hardcoding an instance of Dog. This seems like it might not be possible. Note: I only want one instance of each class.

Thanks for any help in advance.

Update:

This is a way better description of my problem. It also has a solution. I was able to find this with your guy's help. Thanks for the help! At runtime, find all classes in a Java application that extend a base class

Nameis j
  • 65
  • 1
  • 7
  • I think you should consider using the *Java Service Provider Interface* for this, i.e. the `ServiceLoader` class. See the [javadoc](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/ServiceLoader.html), as well as articles at [The Java™ Tutorials](https://docs.oracle.com/javase/tutorial/ext/basics/spi.html) and at [Baeldung](https://www.baeldung.com/java-spi). – Andreas Jun 20 '20 at 03:29
  • 1
    It is better if you could show us what you tried with some code snippets – Klaus Jun 20 '20 at 03:43
  • I will try the recomendations you guys gave. If it doesn't work I will provide an exmaple. – Nameis j Jun 20 '20 at 04:01
  • It seems this question is obsolete as your update suggests you found the answer elsewhere. Please consider to remove the question. – hlg Jun 20 '20 at 10:02

2 Answers2

1

You can use Reflections.

Reflections reflections = new Reflections("cz.milanhlinak.animal");
Set<Class<? extends Animal>> animals = reflections.getSubTypesOf(Animal.class);

See my example repository https://github.com/milanhlinak/62481200 where I use Reflections + Google Guice for dependency injection.

Using Reflections you can get all sub types of your Animal class and add them to Google Guice Multibinder. After that, you can inject them somewhere...

// cz.milanhlinak.Module.java
public class Module extends AbstractModule {

    @Override
    protected void configure() {

        Reflections reflections = new Reflections("cz.milanhlinak.animal");
        Set<Class<? extends Animal>> animals = reflections.getSubTypesOf(Animal.class);

        Multibinder<Animal> animalBinder = Multibinder.newSetBinder(binder(), Animal.class);
        animals.forEach(animal -> animalBinder.addBinding().to(animal));

        bind(AnimalProvider.class).to(AnimalProviderImpl.class).in(Singleton.class);
    }
}

// cz.milanhlinak.animal.Animal.java
public abstract class Animal {

    private final String sound;

    public Animal(String sound) {
        this.sound = sound;
    }

    void makeSound() {
        System.out.println(this.sound);
    }
}

// cz.milanhlinak.animal.Dog.java
public class Dog extends Animal {

    public Dog() {
        super("Bark");
    }
}

// cz.milanhlinak.animal.Cat.java
public class Cat extends Animal {

    public Cat() {
        super("Meow");
    }
}

// cz.milanhlinak.animal.AnimalProvider.java
public interface AnimalProvider {

    Set<Animal> getAnimals();
}

// cz.milanhlinak.animal.AnimalProviderImpl.java
public class AnimalProviderImpl implements AnimalProvider {

    private final Set<Animal> animals;

    @Inject
    public AnimalProviderImpl(Set<Animal> animals) {
        this.animals = animals;
    }

    @Override
    public Set<Animal> getAnimals() {
        return this.animals;
    }
}

You can also check Google Guice - how to automatically add binding where I was looking for something similar, but based on custom annotations.

Milan Hlinák
  • 4,260
  • 1
  • 30
  • 41
0

So you want to add an instance extends Animal to the list in AnimalManager, right?

Make a public method in AnimalManager that get an Animal object as an argument, and add it into its list.

something like: "public void addToList(Animal obj)"

And call it in Animal's constructor. This makes whatever extends Animal would be added to AnimalList if you call super's constructor.