Java - 获取JVM中加载的所有类的列表

时间:2010-03-30 20:16:53

标签: java reflection jvm

我想获得属于某个包以及所有孩子的所有类的列表。这些类可能已经加载,也可能没有加载到JVM中。

11 个答案:

答案 0 :(得分:100)

这不是程序化解决方案,但您可以运行

java -verbose:class ....

并且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]

有关详细信息,请参阅here

答案 1 :(得分:27)

使用Reflections库,它很简单:

Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false));

这将扫描包含my.pkg包的url / s中的所有类。

  • false参数表示 - 不排除默认情况下排除的Object类。
  • 在某些情况下(不同的容器),您可以传递classLoader以及参数。

因此,获取所有类有效地获取Object的所有子类型,传递:

Set<String> allClasses = 
    reflections.getStore().getSubTypesOf(Object.class.getName());

(普通方法reflections.getSubTypesOf(Object.class)会导致将所有类加载到PermGen中,并可能抛出OutOfMemoryError。你不想这样做......)

如果您希望获得Object(或任何其他类型)的所有直接子类型,而不是一次性获取其传递子类型,请使用:

Collection<String> directSubtypes = 
    reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName());

答案 2 :(得分:17)

这个问题有多个答案,部分原因是模糊的问题 - 标题是讨论由JVM加载的类,而问题的内容说&#34; JVM可以加载,也可能不加载#34; ;

假设OP需要由给定类加载器由JVM加载的类,并且只需要那些类 - 我的需要 - 有一个解决方案(elaborated here),如下所示:

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();
        }
    }

}

关于它的一个巧妙的事情是你可以选择你想要检查的任意类加载器。但是,如果类加载器类更改的内部结构可能会中断,那么它将被用作一次性诊断工具。

答案 3 :(得分:7)

我还建议您编写-javagent代理,但使用getAllLoadedClasses方法而不是转换任何类。

要与客户端代码(普通Java代码)同步,请创建套接字并通过它与代理进行通信。然后,您可以在需要时触发“列出所有类”方法。

答案 4 :(得分:6)

上述方法的另一种方法是使用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;
    }
}

这种方法的另一个好处是可以为您提供有关哪个ClassLoader加载给定类的信息。

答案 5 :(得分:3)

如果您已经知道包顶级路径,则使用OpenPojo

final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);

然后你可以浏览列表并执行你想要的任何功能。

答案 6 :(得分:2)

您可能能够获得通过类加载器加载的类的列表,但这不包括尚未加载但在类路径上的类。

要获得类路径上的所有类,您必须执行类似第二个解决方案的操作。如果你真的想要当前“已加载”的类(换句话说,你已经引用,访问或实例化的类),那么你应该优化你的问题以表明这一点。

答案 7 :(得分:2)

在JRockit JVM下运行代码,然后使用JRCMD <PID> print_class_summary

这将输出所有已加载的类,每行一个。

答案 8 :(得分:0)

好吧,我所做的只是列出类路径中的所有文件。它可能不是一个光荣的解决方案,但它可靠地工作,并给我我想要的一切,等等。

答案 9 :(得分:0)

该程序将打印所有具有物理路径的类。如果需要分析来自任何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();
        }
    }
}

答案 10 :(得分:0)

Oracle doc中,您可以使用-Xlog选项,该选项可以写入文件。

java -Xlog:class+load=info:classloaded.txt