【问题标题】:How can I get Class object for every class in a jar如何获取 jar 中每个类的 Class 对象
【发布时间】:2011-10-19 11:16:56
【问题描述】:

我有一个包含 30 个左右类的 jar 文件。我想要的是,在 main 方法的开头,我从这个 jar 中调用一个类,该类使用 Java 的反射功能获取对 jar 中每个类的 Class 引用。我的最终目标是执行某种操作,查询为每个类定义的变量。基本上我正在寻找类似的东西。有没有一种使用标准反射 API 的简单方法来做到这一点,否则制作一个可行的解决方案会很麻烦?

List l = Reflection.getAllClasses();
String var;
foreach(Class c : l) { 
    var = c.getField("fieldname");
    doSomething(var);
}

编辑:

明确一点:代码将从被检查的 jar 中执行。

【问题讨论】:

  • 为什么不在 Jar 文件中包含一个类列表(例如使用Properties 文件)? +1 说明最终目标。
  • @AndrewThompson 因为我不想承担这个管理负担——总是记住文件列表。
  • 编写一个类来准备列表作为构建过程的一部分将是微不足道的。一点负担都没有。
  • @LordDoskias 你有没有用不在类路径上的 jar 来运行它?你能发布你的解决方案吗?

标签: java reflection jar introspection


【解决方案1】:

以下解决方案适用于您的classpath 中或classpath 之外的jar

 try {
        File pathToJar = new File("C:/some.jar");

        JarFile jarFile;
            jarFile = new JarFile(pathToJar);
        Enumeration<JarEntry> e = jarFile.entries();

        URL[] urls = { new URL("jar:file:" + pathToJar+"!/") };
        URLClassLoader cl = URLClassLoader.newInstance(urls);

        while (e.hasMoreElements()) {
            JarEntry je = e.nextElement();
            if(je.isDirectory() || !je.getName().endsWith(".class")){
                continue;
            }
            // -6 because of .class
            String className = je.getName().substring(0,je.getName().length()-6);
            className = className.replace('/', '.');
            System.out.println("Checking for class " + className);
            Class c = cl.loadClass(className);


            System.out.println("Class object " + c.getName());

        }
    } catch (IOException | ClassNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

【讨论】:

    【解决方案2】:

    这对我有用:

    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Enumeration;
    import java.util.jar.JarEntry;
    import java.util.jar.JarFile;
    
    
    public class ClassFinder
    {
        public static void main(String[] args) throws IOException
        {
        Collection<Class<?>> classes = new ArrayList<Class<?>>();
    
        JarFile jar = new JarFile("/home/nono/yamts/yamts.jar");
        for (Enumeration<JarEntry> entries = jar.entries() ; entries.hasMoreElements() ;)
        {
            JarEntry entry = entries.nextElement();
            String file = entry.getName();
            if (file.endsWith(".class"))
            {
                String classname = file.replace('/', '.').substring(0, file.length() - 6);
                try 
                {
                    Class<?> c = Class.forName(classname);
                    classes.add(c);
                }
                catch (Throwable e) 
                {
                    System.out.println("WARNING: failed to instantiate " + classname + " from " + file);
                }
            }
        }
    
        for (Class<?> c : classes)
            System.out.println(c);
        }
    }
    

    【讨论】:

    • 但这适用于外部 jar 文件。如果上述代码将使用与目标相同的 jar 执行怎么办?编辑:您的代码也不适合我。对于每个班级,我都“无法实例化”
    • 只要jar在类路径中,就可以检索类定义。如果指定的 jar 不在类路径中,那么您可能需要为自定义类加载器投入额外的工作。
    • @dagnlies 这个代码有效吗?我也继续无法实例化... Exception java.lang.ClassNotFoundException: com....someclass 当我使用不在类路径上的 jar 并在类路径上运行时
    • @ALM:不知道,在 2011 年确实如此。也许从那时起有些变化。欢迎您调查和增强答案。从我上面的评论来看,jar 显然必须在类路径中。
    • @dagnelies NP 我昨天发帖后想通了:) 我会发布另一个答案。
    【解决方案3】:

    在一个 JAR 文件中列出所有类不是反射可以完成的事情。

    但是,可以使用JarInputStream 来完成。

    【讨论】:

    • 并且也没有 JarInputStream,通过使用 JarFile(如接受的答案所示):)
    • @Grodriguez JarInputStream 可以与 InputStream 一起使用,而无需将 JAR 保存到文件系统,例如new JarInputStream(new URL("https://example.com/my.jar").openStream())...我找不到使用 JarFile 的方法。这个答案肯定有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多