javareflectioninterfacedynamic-class

Create a dynamic class in java


I'm working on a problem where different animal types implement the same talk() method from Animal interface.
If you look at getAnimal() method, you can see that, when a new kind of animal is added to the program, inside of that method has to be changed as well.
I want to add new animals just by subclassing Animal without changing anything in the already existing classes.
For example, add an animal "Dog", criteria="loyal"; talk="woof".
Could you tell me, how it is possible? Below is my code:

interface Animal {

    public void talk();
}

class Lion implements Animal {

    @Override
    public void talk() {
        System.out.println("ROARRRRR");
    }
}

class Mouse implements Animal {

    @Override
    public void talk() {
        System.out.println("SQUEEEEEAK");
    }
}

class Bison implements Animal {

    @Override
    public void talk() {
        System.out.println("BELLOWWWWW");
    }
}

class AnimalType {

    public static Animal getAnimal(String criteria) {

        // I refactor this method
        if (criteria.equals("small")) {
            return new Mouse();
        } else if (criteria.equals("big")) {
            return new Bison();
        } else if (criteria.equals("lazy")) {
            return new Lion();
        }
        return null;
    }
}

public class AnimalExamples {

    public static void main(String[] args) {
        AnimalType.getAnimal("small").talk();
        AnimalType.getAnimal("big").talk();
        AnimalType.getAnimal("lazy").talk();

        //  how to add an animal "Dog" here, criteria="loyal"; talk="woof"
        AnimalType.getAnimal("loyal").talk();

        try {
            AnimalType.getAnimal("small").talk();
        } catch (Exception ex) {
            System.out.println("Animal does not exists");
        }
    }
}

I searched on google, understood it can be done by reflection. But do not know how. If possible, could you help me with this, please? Thanks in advance!


Solution

  • Just so you know runtime class generation is extremely complex and not something recommended for beginners to the language. This would be an excellent scenario to use a map an anonymous classes.

    class AnimalType {
        private static final Map<String, Animal> animals  = new HashMap<String, Animal>();
    
        static {
            // Populating map with default animals
            addAnimal("big","BELLOWWWWW"); // bison
            addAnimal("small","SQUEEEEEAK"); // mouse
            addAnimal("lazy","ROARRRRR"); // lion
            addAnimal("loyal","WOOF "); // dog
        }
    
        public static void addAnimal(String criteria, final String sound) {
            // Assigning a anonymous implementation of animal to the given criteria
            animals.put(criteria, new Animal() {
                @Override
                public void talk() {
                    System.out.println(sound);
                }
            });
        }
    
        public static Animal getAnimal(String criteria) {
            // Returning an animal from the animals map
            return animals.get(criteria);
        }
    }
    

    If you really do insist on true runtime class generation or if you're curious how it works, check out ByteBuddy.