在Java中的包内获取一组类文件[重复]

Posted

技术标签:

【中文标题】在Java中的包内获取一组类文件[重复]【英文标题】:Get a array of class files inside a package in Java [duplicate] 【发布时间】:2012-06-10 06:00:09 【问题描述】:

我需要一个包含在我的 Java 源包中的所有类文件的 Class[]。

我找不到一个标准的方法来一次性完成。如果有人可以编写一个函数来获取该列表将非常有帮助。

Class[] myClasses = yourfunction();  // Return a list of class inside a source package in the currently working project in java

【问题讨论】:

没有标准的方法来枚举给定包中的所有类。在某些情况下,这甚至是不可能的(想想从 HTTP URL 加载类的 URLClassLoader:没有标准化的方法来枚举文件夹中的文件)。 查看此处了解手动解决方法(这不是万无一失的)-***.com/questions/176527/… 【参考方案1】:

我可以使用普通的文件 I/O 和搜索机制来解决这个问题。您可以查看此处发布的答案。

private static List<Class> getClassesForPackage(Package pkg) 
    String pkgname = pkg.getName();

    List<Class> classes = new ArrayList<Class>();

    // Get a File object for the package
    File directory = null;
    String fullPath;
    String relPath = pkgname.replace('.', '/');

    //System.out.println("ClassDiscovery: Package: " + pkgname + " becomes Path:" + relPath);

    URL resource = ClassLoader.getSystemClassLoader().getResource(relPath);

    //System.out.println("ClassDiscovery: Resource = " + resource);
    if (resource == null) 
        throw new RuntimeException("No resource for " + relPath);
    
    fullPath = resource.getFile();
    //System.out.println("ClassDiscovery: FullPath = " + resource);

    try 
        directory = new File(resource.toURI());
     catch (URISyntaxException e) 
        throw new RuntimeException(pkgname + " (" + resource + ") does not appear to be a valid URL / URI.  Strange, since we got it from the system...", e);
     catch (IllegalArgumentException e) 
        directory = null;
    
    //System.out.println("ClassDiscovery: Directory = " + directory);

    if (directory != null && directory.exists()) 

        // Get the list of the files contained in the package
        String[] files = directory.list();
        for (int i = 0; i < files.length; i++) 

            // we are only interested in .class files
            if (files[i].endsWith(".class")) 

                // removes the .class extension
                String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6);

                //System.out.println("ClassDiscovery: className = " + className);

                try 
                    classes.add(Class.forName(className));
                 catch (ClassNotFoundException e) 
                    throw new RuntimeException("ClassNotFoundException loading " + className);
                
            
        
     else 
        try 
            String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", "");
            JarFile jarFile = new JarFile(jarPath);
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) 
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();
                if (entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) 

                    //System.out.println("ClassDiscovery: JarEntry: " + entryName);
                    String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", "");

                    //System.out.println("ClassDiscovery: className = " + className);
                    try 
                        classes.add(Class.forName(className));
                     catch (ClassNotFoundException e) 
                        throw new RuntimeException("ClassNotFoundException loading " + className);
                    
                
            
         catch (IOException e) 
            throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e);
        
    
    return classes;

【讨论】:

太大了,一定有更简单的方法... @Illidanek ya 你绝对可以从这段代码中减少一些代码行,并且可能存在更好的解决方案,即使我希望看到一些更短、更高效的代码来完成同样的工作。跨度> 好答案...节省了我很多时间【参考方案2】:

没有在所有 VM 上尝试此方法,但在最近的 Oracle VM 上,有一种更短的方法:

Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("package/name/with/slashes/instead/dots");
    while (resources.hasMoreElements()) 
        URL url = resources.nextElement();
        System.out.println(url);
        System.out.println(new Scanner((InputStream) url.getContent()).useDelimiter("\\A").next());
    

这将打印出包中资源的名称,因此您可以在它们上使用getResource(...)。调用url.getContent() 将返回sun.net.www.content.text.PlainTextInputStream 的实例,它是VM 特定的类。

【讨论】:

这不适用于 jdk 1.8 下的 jar。 sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream 在尝试读取时抛出 NPE。

以上是关于在Java中的包内获取一组类文件[重复]的主要内容,如果未能解决你的问题,请参考以下文章

spring项目jar包内的配置文件和项目的配置文件有重复项

如何在Java生成的文件中更改android中的包名称[重复]

Java集合框架

Java集合框架1

类集框架1

Java集合类