Java - 获取 JVM 中加载的所有类的列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2548384/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java - Get a list of all Classes loaded in the JVM
提问by
I would like to get a list of all the classes belonging to a certain package as well as all of their children. The classes may or may not be already loaded in the JVM.
我想获得属于某个包的所有类及其所有子类的列表。这些类可能已加载或未加载到 JVM 中。
采纳答案by daveb
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.
好吧,我所做的只是列出类路径中的所有文件。这可能不是一个出色的解决方案,但它工作可靠,并为我提供了我想要的一切,等等。
回答by Brian Agnew
It's not a programmatic solution but you can run
这不是一个程序化的解决方案,但您可以运行
java -verbose:class ....
and the JVM will dump out what it's loading, and from where.
并且 JVM 将转储它正在加载的内容以及从何处加载。
[Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar]
[Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
See herefor more details.
请参阅此处了解更多详情。
回答by Bill K
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.
要在类路径上获取所有类,您必须执行类似于第二个解决方案的操作。如果您真的想要当前“已加载”的类(换句话说,您已经引用、访问或实例化的类),那么您应该完善您的问题以表明这一点。
回答by Amir Afghani
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:
上述方法的另一种方法是创建一个外部代理,java.lang.instrument
用于找出加载了哪些类并使用-javaagent
开关运行您的程序:
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.
这种方法还有一个额外的好处,即为您提供有关哪个 ClassLoader 加载给定类的信息。
回答by daveb
I'd also suggest you write a -javagent
agent, but use the getAllLoadedClassesmethod instead of transforming any classes.
我还建议您编写一个-javagent
代理,但使用getAllLoadedClasses方法而不是转换任何类。
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.
要与您的客户端代码(普通 Java 代码)同步,请创建一个套接字并通过它与代理进行通信。然后,您可以在需要时触发“列出所有类”方法。
回答by mgaert
Run your code under a JRockit JVM, then use JRCMD <PID> print_class_summary
在 JRockit JVM 下运行您的代码,然后使用 JRCMD <PID> print_class_summary
This will output all loaded classes, one on each line.
这将输出所有加载的类,每行一个。
回答by Osman Shoukry
回答by zapp
using the Reflectionslibrary, it's easy as:
使用Reflections库,这很简单:
Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false));
That would scan all classes in the url/s that contains my.pkg package.
这将扫描包含 my.pkg 包的 url/s 中的所有类。
- the false parameter means - don't exclude the Object class, which is excluded by default.
- in some scenarios (different containers) you might pass the classLoader as well as a parameter.
- false 参数表示 - 不排除默认情况下排除的 Object 类。
- 在某些情况下(不同的容器),您可能会传递 classLoader 以及一个参数。
So, getting all classes is effectively getting all subtypes of Object, transitively:
因此,获取所有类实际上是获取 Object 的所有子类型,传递性:
Set<String> allClasses =
reflections.getStore().getSubTypesOf(Object.class.getName());
(The ordinary way reflections.getSubTypesOf(Object.class)
would cause loading allclasses into PermGen and would probably throw OutOfMemoryError. you don't want to do it...)
(普通方法reflections.getSubTypesOf(Object.class)
会导致将所有类加载到 PermGen 中,并且可能会抛出 OutOfMemoryError。你不想这样做......)
If you want to get all directsubtypes of Object (or any other type), without getting its transitive subtypes all in once, use this:
如果您想获得Object(或任何其他类型)的所有直接子类型,而不是一次性获得其可传递的子类型,请使用以下命令:
Collection<String> directSubtypes =
reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName());
回答by eis
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".
这个问题有多种答案,部分原因是问题含糊不清——标题是在谈论 JVM 加载的类,而问题的内容是“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:
假设 OP 需要由给定类加载器由 JVM 加载的类,并且只有那些类 - 我也需要 - 有一个解决方案(在此处详细说明),如下所示:
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
public class CPTest {
private static Iterator list(ClassLoader CL)
throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Class CL_class = CL.getClass();
while (CL_class != java.lang.ClassLoader.class) {
CL_class = CL_class.getSuperclass();
}
java.lang.reflect.Field ClassLoader_classes_field = CL_class
.getDeclaredField("classes");
ClassLoader_classes_field.setAccessible(true);
Vector classes = (Vector) ClassLoader_classes_field.get(CL);
return classes.iterator();
}
public static void main(String args[]) throws Exception {
ClassLoader myCL = Thread.currentThread().getContextClassLoader();
while (myCL != null) {
System.out.println("ClassLoader: " + myCL);
for (Iterator iter = list(myCL); iter.hasNext();) {
System.out.println("\t" + iter.next());
}
myCL = myCL.getParent();
}
}
}
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.
关于它的一个巧妙之处是您可以选择要检查的任意类加载器。然而,如果类加载器类的内部结构发生变化,它可能会中断,因此它被用作一次性诊断工具。
回答by user8778576
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.
该程序将打印所有类及其物理路径。如果您需要分析从任何 Web/应用程序服务器加载的类,use 可以简单地将其复制到任何 JSP。
import java.lang.reflect.Field;
import java.util.Vector;
public class TestMain {
public static void main(String[] args) {
Field f;
try {
f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes = (Vector<Class>) f.get(classLoader);
for(Class cls : classes){
java.net.URL location = cls.getResource('/' + cls.getName().replace('.',
'/') + ".class");
System.out.println("<p>"+location +"<p/>");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}