Java - получить список всех классов, загруженных в JVM

Я хотел бы получить список всех классов, принадлежащих определенному пакету, а также всем своим детям. Классы могут или не могут быть уже загружены в JVM.

Ответ 1

Хорошо, что я сделал, просто перечислял все файлы в пути к классам. Это может быть не славное решение, но оно работает надежно и дает мне все, что я хочу, и многое другое.

Ответ 2

Это не программное решение, но вы можете запустить

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]

Подробнее см. здесь.

Ответ 3

используя библиотеку Reflections, это легко:

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

Это сканирует все классы в url/s, которые содержат пакет my.pkg.

  • параметр false - не исключает класс Object, который по умолчанию исключается.
  • в некоторых сценариях (разных контейнерах) вы можете передать classLoader, а также параметр.

Итак, получение всех классов эффективно получает все подтипы Object, транзитивно:

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

(Обычный способ reflections.getSubTypesOf(Object.class) приведет к загрузке классов all в PermGen и, вероятно, вызовет OutOfMemoryError, вы не захотите это делать...)

Если вы хотите получить все прямые подтипы объекта (или любого другого типа), не получая его транзитивных подтипов за один раз, используйте это:

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

Ответ 4

Есть несколько ответов на этот вопрос, отчасти из-за неоднозначного вопроса - заголовок говорит о классах, загружаемых JVM, тогда как содержание вопроса говорит "может или не может быть загружено JVM".

Предполагая, что 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();
        }
    }

}

Одна из опрятных вещей заключается в том, что вы можете выбрать произвольный загрузчик классов, который хотите проверить. Тем не менее, вероятно, он будет разрушен, если внутренние классы класса classload меняются, поэтому он должен использоваться как одноразовый диагностический инструмент.

Ответ 5

Альтернативный подход к описанным выше может заключаться в создании внешнего агента, использующего 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 загружал данный класс.

Ответ 6

Я также предлагаю вам написать агент -javagent, но используйте getAllLoadedClasses вместо преобразования любых классов.

Чтобы синхронизировать с вашим кодом клиента (обычный код Java), создайте сокет и обменивайтесь с ним агентом. Затем вы можете запускать метод "список всех классов", когда вам нужно.

Ответ 7

В одном случае, если вы уже знаете путь верхнего уровня пакета, используйте OpenPojo

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

Затем вы можете просмотреть список и выполнить любую функциональность, которую вы хотите.

Ответ 8

Возможно, вы сможете получить список классов, загружаемых через загрузчик классов, но это не будет включать классы, которые вы еще не загрузили, но находятся в вашем пути к классам.

Чтобы получить ВСЕ классы в вашем пути к классам, вы должны сделать что-то вроде своего второго решения. Если вам действительно нужны классы, которые в настоящее время "загружены" (другими словами, классы, на которые вы уже ссылались, обращались к ним или инстанцировались), вы должны уточнить свой вопрос, чтобы указать это.

Ответ 9

Запустите свой код под JRockit JVM, затем используйте JRCMD <PID> print_class_summary

Это приведет к выводу всех загруженных классов, по одному в каждой строке.

Ответ 10

Эта программа будет печатать все классы с ее физическим путем. использование может просто скопировать это в любой 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();
        }
    }
}