Java 在Jar中查找实现接口的类

Java 在Jar中查找实现接口的类,java,interface,jar,Java,Interface,Jar,我想知道jar中的类是否实现了特定的接口。我已经实现了下面的代码,但它会迭代jar文件中的所有类,并在每个类上查找它是否实现了这个特定接口 public static synchronized boolean findClassesInJar(final Class<?> baseInterface, final String jarName){ final List<String> classesTobeReturned = new ArrayL

我想知道jar中的类是否实现了特定的接口。我已经实现了下面的代码,但它会迭代jar文件中的所有类,并在每个类上查找它是否实现了这个特定接口

    public static synchronized boolean findClassesInJar(final Class<?> baseInterface, final String jarName){
        final List<String> classesTobeReturned = new ArrayList<String>();
        if (!StringUtils.isBlank(jarName)) {
            //jarName is relative location of jar wrt. 
            final String jarFullPath = File.separator + jarName;
            final ClassLoader classLoader = this.getClassLoader();
            JarInputStream jarFile = null;
            URLClassLoader ucl = null;
            final URL url = new URL("jar:file:" + jarFullPath + "!/");
            ucl = new URLClassLoader(new URL[] { url }, classLoader);
            jarFile = new JarInputStream(new FileInputStream(jarFullPath));
            JarEntry jarEntry;
            while (true) {
                jarEntry = jarFile.getNextJarEntry();
                if (jarEntry == null)
                    break;
                if (jarEntry.getName().endsWith(".class")) {
                    String classname = jarEntry.getName().replaceAll("/", "\\.");
                    classname = classname.substring(0, classname.length() - 6);
                    if (!classname.contains("$")) {
                        try {
                            final Class<?> myLoadedClass = Class.forName(classname, true, ucl);
                            if (baseInterface.isAssignableFrom(myLoadedClass)) {
                                return true;
                            }
                        } catch (final ClassNotFoundException e) {

                        } 
                    }
                }
            }
        return false;
    }
public静态同步布尔findClassesInJar(最终类baseInterface,最终字符串jarName){
final List classesTobeReturned=new ArrayList();
如果(!StringUtils.isBlank(jarName)){
//jarName是jarwrt的相对位置。
最终字符串jarFullPath=File.separator+jarName;
final ClassLoader ClassLoader=this.getClassLoader();
JarInputStream jarFile=null;
URLClassLoader ucl=null;
最终URL=新URL(“jar:file:+jarFullPath+”!/”;
ucl=新的URLClassLoader(新的URL[]{URL},类加载器);
jarFile=newjarinputstream(newfileinputstream(jarFullPath));
JarEntry-JarEntry;
while(true){
jarEntry=jarFile.getNextJarEntry();
if(jarEntry==null)
打破
if(jarEntry.getName().endsWith(“.class”)){
字符串classname=jarEntry.getName().replaceAll(“/”,“\\”);
classname=classname.substring(0,classname.length()-6);
如果(!classname.contains($)){
试一试{
最终类myLoadedClass=Class.forName(classname,true,ucl);
if(baseInterface.isAssignableFrom(myLoadedClass)){
返回true;
}
}捕获(最终类NotFound异常e){
} 
}
}
}
返回false;
}
有什么简单的方法可以做到这一点吗?因为如果有一个包含100个类文件的jar,并且第100个类已经实现了这个接口,那么通过上面的代码,我需要迭代所有的100个类文件,看看它是否实现了这个接口。有什么有效的方法可以做到这一点吗?

任何现代IDE(eclipse,IntelliJ,…)应该能够找到特定接口(或类或方法)的用法

如果您有jar文件的源,您可以将其作为依赖项添加到项目中。或者,您可以简单地解压缩jar的内容,并在IDE中作为项目打开它,然后找到您感兴趣的接口的用法。

库可以这样做:

Reflections reflections = new Reflections(
    ClasspathHelper.forPackage("your.root.package"), new SubTypesScanner());
Set<Class<? extends YourInterface>> implementingTypes =
     reflections.getSubTypesOf(YourInterface.class);
反射=新反射(
ClasspathHelper.forPackage(“your.root.package”),新的子类扫描程序();

一般来说,没有简单的方法。甚至没有一种获取信息的通用方法


这里的问题在于Java的类加载机制。在实际加载一个类之前,你无法判断它是否实现了一个接口。如果不尝试加载一个类,你也无法判断它是否存在(请注意,你甚至无法判断类路径上有哪些类可用)

这里的原因很简单,类加载器不提供任何枚举类功能,原因是类路径可能无限大/无限深,检索该枚举的成本(时间上)可能无限大(请考虑将您连接到大型远程代码存储库的URL类加载器)


因此,您的方法已经尽可能好了。

Spring在
ClassPathScanningCandidateComponentProvider
中为此提供了一些帮助程序代码,但它基本上完成了您所做的工作

您可能还想看看哪个是编写静态分析测试的合适工具包,比如确保某个包中的所有类或实现某个接口的类也实现了
equals()
hashCode()


Freud的好处在于,它可以分析Java源文件和类文件(即源代码和编译的字节码),它可以查看属性或文本文件,它可以读取CSS和Spring配置(因此它可以确保DAOBean的所有重要方法都具有
@Transactional
).

您可以使用IntelliJ进行此操作。创建一个虚拟项目,并将JAR添加到类路径。然后打开您的界面,并单击界面名称左侧的(I)图标。不确定是否使用eCILSE,但非常确定您可以这样做

课程也是如此


您需要动态执行此操作吗?IDE不是一个选项吗?不,没有。没有内置的索引功能,您可以在O(1)中查找。您是否尝试过查看?我希望使用java代码动态执行此操作。我使用此方法-我对问题的理解是,OP正在寻找一种比O(n)运行更好的方法。我不确定反射库是如何实现的,但从这段代码的外观来看,我认为它的效率低于OP的当前代码。@Vulcan-OP提出了两个问题-一个更简单的解决方案和一个更有效的解决方案。这肯定更简单。@Vulcan a)我在问题中找不到这个假设n b)reflections是一个稳定的库,在生产中大量使用。它的效率与此类库一样高be@Vulcan首先,OP实际上加载所有类,而任何合理的库(包括反射)他只会检查班级metadata@Durandal类是一种具有良好定义格式的二进制资源,不需要实际加载一个类来读取该格式,事实上,不加载所有类要快得多。“在实际加载一个类之前,你无法判断该类是否实现了接口。”这是完全不正确的。如果是这样的话,许多像Spring这样的现代框架就不能正常工作。Spring使用它来读取它的类元数据,并且它不会在这一步中加载类。反射库