Can I do it with reflection or something like that?
Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class. By convention, the implements clause follows the extends clause, if there is one.
Since List is an interface, objects cannot be created of the type list. We always need a class that implements this List in order to create an object. And also, after the introduction of Generics in Java 1.5, it is possible to restrict the type of object that can be stored in the List.
When you call a method on a variable declared as an interface, Java will look up which method to call in the instance's vtable, which is set when you create the instance based on the class. Thus, it actually calls the implementation definde by the class that that object is an instance of at runtime.
I have been searching for a while and there seems to be different approaches, here is a summary:
reflections library is pretty popular if u don't mind adding the dependency. It would look like this:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections"); Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader (as per erickson answer) and it would look like this:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class); for (Pet implClass : loader) { System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat }
Note that for this to work you need to define Pet
as a ServiceProviderInterface (SPI) and declare its implementations. you do that by creating a file in resources/META-INF/services
with the name examples.reflections.Pet
and declare all implementations of Pet
in it
examples.reflections.Dog examples.reflections.Cat
package-level annotation. here is an example:
Package[] packages = Package.getPackages(); for (Package p : packages) { MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class); if (annotation != null) { Class<?>[] implementations = annotation.implementationsOfPet(); for (Class<?> impl : implementations) { System.out.println(impl.getSimpleName()); } } }
and the annotation definition:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PACKAGE) public @interface MyPackageAnnotation { Class<?>[] implementationsOfPet() default {}; }
and you must declare the package-level annotation in a file named package-info.java
inside that package. here are sample contents:
@MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class}) package examples.reflections;
Note that only packages that are known to the ClassLoader at that time will be loaded by a call to Package.getPackages()
.
In addition, there are other approaches based on URLClassLoader that will always be limited to classes that have been already loaded, Unless you do a directory-based search.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With