Quiero hacer algo como esto:
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() );
Entonces, quiero ver todas las clases en el universo de mi aplicación, y cuando encuentro una que desciende de Animal, quiero crear un nuevo objeto de ese tipo y agregarlo a la lista. Esto me permite agregar funcionalidad sin tener que actualizar una lista de cosas. Puedo evitar lo siguiente:
List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...
Con el enfoque anterior, simplemente puedo crear una nueva clase que extienda Animal y se recogerá automáticamente.
ACTUALIZACIÓN: 16/10/2008 9:00 am Hora estándar del Pacífico:
Esta pregunta ha generado muchas respuestas excelentes, gracias. A partir de las respuestas y mi investigación, descubrí que lo que realmente quiero hacer no es posible con Java. Hay enfoques, como el mecanismo ServiceLoader de ddimitrov que pueden funcionar, pero son muy pesados para lo que quiero, y creo que simplemente muevo el problema del código Java a un archivo de configuración externo. Actualización 5/10/19 (¡11 años después!) Ahora hay varias bibliotecas que pueden ayudar con esto según la respuesta de @ IvanNik org.reflections se ve bien. También ClassGraph de la respuesta de @Luke Hutchison parece interesante. Hay varias posibilidades más en las respuestas también.
Otra forma de decir lo que quiero: una función estática en mi clase Animal encuentra e instancia todas las clases que heredan de Animal, sin ninguna configuración / codificación adicional. Si tengo que configurar, igual podría instanciarlos en la clase Animal de todos modos. Entiendo que debido a que un programa Java es solo una federación suelta de archivos .class, así es como es.
Curiosamente, parece que esto es bastante trivial en C #.