I want to do something like this:
List<Animal> animals = new ArrayList<Animal>();
for( Class c: list_of_all_classes_available_to_my_app() )
if (c is Animal)
animals.add( new c() );
So, I want to look at all of the classes in my application's universe, and when I find one that descends from Animal, I want to create a new object of that type and add it to the list. This allows me to add functionality without having to update a list of things. I can avoid the following:
List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...
With the above approach, I can simply create a new class that extends Animal and it'll get picked up automatically.
UPDATE: 10/16/2008 9:00 a.m. Pacific Standard Time:
This question has generated a lot of great responses -- thank you. From the responses and my research, I've found that what I really want to do is just not possible under Java. There are approaches, such as ddimitrov's ServiceLoader mechanism that can work -- but they are very heavy for what I want, and I believe I simply move the problem from Java code to an external configuration file. Update 5/10/19 (11 years later!) There are now several libraries that can help with this according to @IvanNik's answer org.reflections looks good. Also ClassGraph from @Luke Hutchison's answer looks interesting. There are several more possibilities in the answers as well.
Another way to state what I want: a static function in my Animal class finds and instantiates all classes that inherit from Animal -- without any further configuration/coding. If I have to configure, I might as well just instantiate them in the Animal class anyway. I understand that because a Java program is just a loose federation of .class files that that's just the way it is.
Interestingly, it seems this is fairly trivial in C#.