是否有可能找到给定包中的所有类或接口?(快速看了一下e.g. Package,似乎没有。)


当前回答

不使用任何额外的库:

package test;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) throws Exception{
        List<Class> classes = getClasses(Test.class.getClassLoader(),"test");
        for(Class c:classes){
            System.out.println("Class: "+c);
        }
    }

    public static List<Class> getClasses(ClassLoader cl,String pack) throws Exception{

        String dottedPackage = pack.replaceAll("[/]", ".");
        List<Class> classes = new ArrayList<Class>();
        URL upackage = cl.getResource(pack);

        DataInputStream dis = new DataInputStream((InputStream) upackage.getContent());
        String line = null;
        while ((line = dis.readLine()) != null) {
            if(line.endsWith(".class")) {
               classes.add(Class.forName(dottedPackage+"."+line.substring(0,line.lastIndexOf('.'))));
            }
        }
        return classes;
    }
}

其他回答

谷歌Guava 14包含了一个新类ClassPath,它有三个方法来扫描顶级类:

getTopLevelClasses () getTopLevelClasses(管柱packageName) getTopLevelClassesRecursive(管柱packageName)

有关更多信息,请参阅ClassPath javadocs。

是的,你可以使用很少的API,这是我喜欢做的,面对这个问题,我使用hibernate核心&必须找到类,其中注释了某个注释。

使这些自定义注释使用,您将标记哪些类您想要获得。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EntityToBeScanned {

}

然后用它来标记你的课

@EntityToBeScanned 
public MyClass{

}

创建具有以下方法的实用程序类

public class ClassScanner {

    public static Set<Class<?>> allFoundClassesAnnotatedWithEntityToBeScanned(){
        Reflections reflections = new Reflections(".*");
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(EntityToBeScanned.class);
        return annotated;
    }

}

调用allfoundclassesannotatedwithentitytobescans()方法获取找到的类集。

你将需要下列的参考书目

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>21.0</version>
    </dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.22.0-CR1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>

春天

这个例子是针对Spring 4的,但是您也可以在早期版本中找到类路径扫描器。

// create scanner and disable default filters (that is the 'false' argument)
final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
// add include filters which matches all the classes (or use your own)
provider.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile(".*")));

// get matching classes defined in the package
final Set<BeanDefinition> classes = provider.findCandidateComponents("my.package.name");

// this is how you can load the class type from BeanDefinition instance
for (BeanDefinition bean: classes) {
    Class<?> clazz = Class.forName(bean.getBeanClassName());
    // ... do your magic with the class ...
}

谷歌番石榴

注意:在版本14中,API仍然被标记为@Beta,所以在生产代码中要小心。

final ClassLoader loader = Thread.currentThread().getContextClassLoader();

for (final ClassPath.ClassInfo info : ClassPath.from(loader).getTopLevelClasses()) {
  if (info.getName().startsWith("my.package.")) {
    final Class<?> clazz = info.load();
    // do something with your clazz
  }
}

如果您不使用任何动态类加载器,您可以搜索类路径,并为每个条目搜索目录或JAR文件。

基于@Staale的回答,为了不依赖第三方库,我将通过检查第一个包的物理位置来实现文件系统方法:

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
...
Class<?>[] foundClasses = new Class<?>[0];
final ArrayList<Class<?>> foundClassesDyn = new ArrayList<Class<?>>();

new java.io.File(
    klass.getResource(
        "/" + curPackage.replace( "." , "/")
    ).getFile()
).listFiles(
    new java.io.FileFilter() {
        public boolean accept(java.io.File file) {
            final String classExtension = ".class";

            if ( file.isFile()
                && file.getName().endsWith(classExtension)
                // avoid inner classes
                && ! file.getName().contains("$") )
            {
                try {
                    String className = file.getName();
                    className = className.substring(0, className.length() - classExtension.length());
                    foundClassesDyn.add( Class.forName( curPackage + "." + className ) );
                } catch (ClassNotFoundException e) {
                    e.printStackTrace(System.out);
                }
            }

            return false;
        }
    }
);

foundClasses = foundClassesDyn.toArray(foundClasses);