Как найти имя пакета по названию класса? - PullRequest
9 голосов
/ 05 января 2012

Если имя класса задано в виде строки, как мне получить его имя во время выполнения? У меня нет полного имени с именем пакета + имя класса. Просто только имя класса.

Я хочу, чтобы имя пакета использовалось в методе Class.forName().

У меня все в порядке с поиском первого подходящего имени пакета (если несколько пакетов имеют один и тот же класс).

Есть идеи?

UPDATE

У меня нет экземпляра класса для работы. Мое требование - создать класс, используя метод Class.forName(). Но у меня просто есть ТОЛЬКО имя класса в виде строки. Мне нужен какой-то способ зациклить пакеты и определить, принадлежит ли мой класс к пакету.

Трассировка стека исключительной ситуации

Exception in thread "main" java.lang.ClassNotFoundException: MyAddressBookPage
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)

Ответы [ 5 ]

10 голосов
/ 05 января 2012

Скорее всего, это невероятно неэффективный, раздутый, неудобный способ сделать то, что вы пытаетесь достичь, и, надеюсь, уже есть готовый, единственный способ сделать это ... но он должен работать .

По сути, просматривайте все классы в пути к классам, пока не найдете класс, в котором getSimpleName() соответствует имени класса, который у вас есть.

Я рекомендую взглянуть на Google Classpath Explorer , чтобы помочь разобраться в этом.

Это может выглядеть примерно так:

 ClassPath classpath = new ClassPathFactory().createFromJVM();
 RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter(".*", ".*\\.class");
 String[] resources = classpath.findResources("", regExpResourceFilter);

resources - это массив строк, например 'com / foo / bar / Baz.class'. Теперь вы можете просто перебрать и найти подходящие записи и преобразовать их из косой в пунктирную, вырезать «.class» и т. Д. Просто будьте осторожны, пытаясь сопоставить внутренние классы, поскольку в них будет символ «$».

Кроме того, насколько мне известно, это НЕ приведет к загрузке этих классов.

8 голосов
/ 05 января 2012
 final Package[] packages = Package.getPackages();
    final String className = "ArrayList";

    for (final Package p : packages) {
        final String pack = p.getName();
        final String tentative = pack + "." + className;
        try {
            Class.forName(tentative);
        } catch (final ClassNotFoundException e) {
            continue;
        }
        System.out.println(pack);
        break;
    }
3 голосов
/ 05 января 2012

Единственным способом было бы перемещаться по каталогам / банкам в classpath и записи с именем класса.

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

public Class<?> locateImplementation(Class<?> type) {
     Class<?> c = null;
     String[] cp = System.getProperty("java.class.path").split(File.pathSeparator);

     for (int i = 0; (c == null) && (i < cp.length); ++i) {
         File f = new File(cp[i]);
         if (f.exists() && f.canRead()) {
             if (isJar(f)) {
                 try {
                     c = searchJar(type, new FileInputStream(f));
                 } catch (Throwable t) {
                     // Nothing to worry about
                 }
             } else {
                 c = searchFile(type, f);
             }
         }
     }

     return c;
 }

private boolean isClass(String path) {
    return path.matches(".+\\.class$") && !path.contains("$");
}

private Class<?> searchFile(Class<?> type, File f) {
    return searchFile(type, f, f.getPath());
}

private Class<?> searchFile(Class<?> type, File f, String root) {
    Class<?> implementation = null;

    if (f.isDirectory()) {
        File[] files = f.listFiles();
        for (int i = 0; i < files.length; i++) {
            implementation = searchFile(type, files[i], root);
            if (implementation != null) {
                break;
            }
        }
    } else if (isClass(f.getPath())) {
        String path = f.getPath().substring(root.length() + 1);
        Class<?> c = getClass(path);
        if ((c != null) && !c.isInterface() &&
                type.isAssignableFrom(c)) {
            implementation = c;
        }
    }
    return implementation;
}

private Class<?> getClass(String name) {
    Class<?> c;
    String className = name.replaceAll("[/\\\\]", ".")
        .replaceFirst("^\\.", "").replace(".class", "");
    try {
        c = Class.forName(className);
    } catch (Throwable e) {
        c = null;
    }

    return c;
}


private Class<?> searchJar(Class<?> type, InputStream in)
        throws Exception {
    ZipInputStream zin = new ZipInputStream(in);
    Class<?> implementation = null;

    ZipEntry ze;
    while ((implementation == null)
            && ((ze = zin.getNextEntry()) != null)) {
        String name = ze.getName();
        if (name.endsWith("class")
                && name.matches("^com.xxx.+")
                && !name.contains("$")) {
            try {
                Class<?> c = getClass(name);
                if ((c != null) && !c.isInterface()
                        && type.isAssignableFrom(c)) {
                    implementation = c;
                }
            } catch (Throwable t) {
                // Nothing to worry about
            }
        }
    }

    return implementation;
}

private boolean isJar(File f) {
    return f.getPath().endsWith(".jar");
}
0 голосов
/ 01 апреля 2018

Вызовите getPackageName () для класса.Возвращает полное имя пакета.Также стоит упомянуть, что это функция Java 9.

0 голосов
/ 30 января 2015

Одно из самых простых решений:

Test.class.toString().replace("class", "").replace(".","/").replace(" ", "")
...