For example, there is an interface "Apartment".
You need to go through all types of apartments that inherit the "Apartment" interface, (one, two, three, etc.) and, say, add them to the ArrayList .

Is it possible to do this? If so, how?

  • one
    This can only be done by third-party libs with hellish reflection . Most likely, your task can be solved more elegantly if you reveal more details. - Yuriy SPb
  • @Yuriy SPb, but if they were written by people, then it is possible without lib. Just two lines will not do. - Nofate
  • @Nofate, well, I meant it about it - without a long time, and everything that is connected with reflection I, in my practice, always caused by ignorance of how to solve a problem without it) - YuriySPb
  • It is very similar to the fact that you reinvent dependency injection. - enzo

2 answers 2

It is realizable. This can even be useful when you write some extensible framework and do not know in advance what objects you will have to work with, and forcing the user to register classes manually (as it happens, for example, in JDBC) is unacceptable for some reason.

In general, you need:

  1. Run CLASSPATH scan
  2. Check all found classes through reflection on interface / class inheritance.
  3. Call through the constructor reflection.

Immediately you should understand: either you know (require) which constructor will be implemented in all classes, or use the default constructor without parameters (and it is created automatically only if there are no other explicit constructors).

Items 1 and 2 are somewhat tedious to implement manually. Fortunately, there is an excellent Reflections library that allows you to do this in two lines of code. Suppose we are interested in all implementations of the HttpHandler interface:

 Reflections reflections = new Reflections(); Set<Class<? extends HttpHandler>> classes = reflections.getSubTypesOf(HttpHandler.class); 

And that's it! Now it remains to iterate over all instances of Class and call, say a constructor without parameters:

 List<HttpHandler> handlers = new ArrayList<>(); for (Class<? extends HttpHandler> clazz : classes) { try { handlers.add(clazz.newInstance()); } catch (InstantiationException | IllegalAccessException e) { System.out.println("Не удалось создать экземпляр: " + clazz.getCanonicalName()); } } 

But!

If you are not yet writing your frameworks, then there is a chance that you are somehow wrong, breaking OOP, trying to solve a completely different problem .


Alternative implementations of the CLASSPATH scanner:

    The following method finds all classes located in the specified jar archive that implement a specific interface:

     Collection<Class<?>> getAllInterfaceImplementations(String pathToJar, Class<?> interfaceType) throws Exception { JarFile jarFile = new JarFile(pathToJar); Enumeration<JarEntry> e = jarFile.entries(); URL[] urls = {new URL("jar:file:" + pathToJar + "!/")}; URLClassLoader cl = URLClassLoader.newInstance(urls); Collection<Class<?>> classes = new ArrayList<>(); while (e.hasMoreElements()) { JarEntry je = e.nextElement(); if (je.isDirectory() || !je.getName().endsWith(".class")) continue; String className = je.getName().substring(0, je.getName().length() - ".class".length()); className = className.replace('/', '.'); Class type = cl.loadClass(className); if (interfaceType.isAssignableFrom(type)) classes.add(type); } return classes; } 

    Use this:

     String pathToJar = "<путь до JAVA_HOME>/rt.jar"; for (Class<?> type : getAllInterfaceImplementations(pathToJar, Collection.class)) System.out.println(type.getName());