You might be able to get a list of classes that are loaded through the classloader but this would not include classes you haven't loaded yet but are on your classpath.
To get ALL classes on your classpath you have to do something like your second solution. If you really want classes that are currently "Loaded" (in other words, classes you have already referenced, accessed or instantiated) then you should refine your question to indicate this.
An alternative approach to those described above would be to create an external agent using java.lang.instrument to find out what classes are loaded and run your program with the -javaagent switch:
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class SimpleTransformer implements ClassFileTransformer {
public SimpleTransformer() {
super();
}
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
System.out.println("Loading class: " + className);
return bytes;
}
}
This approach has the added benefit of providing you with information about which ClassLoader loaded a given class.
I'd also suggest you write a -javagent agent, but use the getAllLoadedClasses method instead of transforming any classes.
To synchronize with your client code (Normal Java code), create a socket and communicate with the agent through it. Then you can trigger a "list all classes" method whenever you need.
Well, what I did was simply listing all the files in the classpath. It may not be a glorious solution, but it works reliably and gives me everything I want, and more.
(The ordinary way reflections.getSubTypesOf(Object.class) would cause loading all classes into PermGen and would probably throw OutOfMemoryError. you don't want to do it...)
If you want to get all direct subtypes of Object (or any other type), without getting its transitive subtypes all in once, use this:
There are multiple answers to this question, partly due to ambiguous question - the title is talking about classes loaded by the JVM, whereas the contents of the question says "may or may not be loaded by the JVM".
Assuming that OP needs classes that are loaded by the JVM by a given classloader, and only those classes - my need as well - there is a solution (elaborated here) that goes like this:
One of the neat things about it is that you can choose an arbitrary classloader you want to check. It is however likely to break should internals of classloader class change, so it is to be used as one-off diagnostic tool.
This program will prints all the classes with its physical path. use can simply copy this to any JSP if you need to analyse the class loading from any web/application server.
If you don't want any libraries and need this information given to you at runtime, you can use this for Java 11+. It finds all system modules loaded at runtime, iterates over their entries (path names) and collects class items.
public static List<String> getSystemClasses() {
// Errorables is a util class to ignore exceptions on lambda types, easy enough to implement yourself
return ModuleFinder.ofSystem().findAll().stream()
.map(modRef -> Errorables.silent(modRef::open)) // open reader to each module
.flatMap(modReader -> Errorables.silent(modReader::list)) // list all items in the module
.filter(s -> s.endsWith(".class") && s.indexOf('-') == -1) // retain only classes (except module-info or package-info)
.map(s -> s.substring(0, s.length() - 6)) // cut off '.class' from the path
.collect(Collectors.toList());
}
If you need non-system classes then there are some conditions to consider. In both situations you can use a class reference to something in your project to get the needed context to find other classes.
If you want only the currently loaded classes, you can use reflection to access the Vector<Class<?>> classes in ClassLoader. This will not include classes from libraries and such that have not yet been initialized.
If you want all classes of all libraries you have in a project then you'll want to use reflection to access the AppClassLoader's URLClassPath ucp. This will hold a ArrayList<URL> path containing URL's pointing to every directory/jar/etc holding referenced resources. Navigating those you can use path-walking to collect the names of class entries similar to the code snippet above.