不使用第三方,不使用属性文件,不指定包名,获取整个系统中某一个接口所有的实现类,纯Java实现
java
/**
* 类查找器,用于扫描类路径中的所有类,并找出指定类的实现类。
* 该类通过递归扫描类路径下的所有 .class 文件,加载并判断是否为目标类的实现类。
*/
public class ClassFinder {
/**
* 获取指定类的所有实现类(非接口本身)。
* 从类路径根目录开始扫描,使用当前线程的类加载器获取资源路径。
*
* @param clazz 要查找实现类的目标类(通常是抽象类或接口)
* @return 返回目标类的所有实现类组成的列表
*/
public static List<Class<?>> getImplementationsOfMyService(Class<?> clazz) {
List<Class<?>> implementations = new ArrayList<>();
// 设置为空字符串表示从类路径根开始扫描
String packageName = "";
// 使用当前线程的类加载器加载类资源
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resources = null;
try {
// 获取类路径下对应包名的资源路径(转换为文件系统路径格式)
resources = classLoader.getResources(packageName.replace('.', '/'));
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
File file = new File(resource.getFile());
// 开始递归扫描该目录下的类文件
scanDirectory(clazz, file, "", implementations);
}
} catch (IOException e) {
e.printStackTrace();
}
return implementations;
}
/**
* 递归扫描目录及其子目录中的类文件。
* 对每个类文件进行加载并判断是否是目标类的实现类。
*
* @param clazz 目标类(要查找其实现类)
* @param dir 当前扫描的目录
* @param pkg 当前目录对应的包名前缀
* @param list 存储符合条件的实现类
*/
private static void scanDirectory(Class<?> clazz, File dir, String pkg, List<Class<?>> list) {
if (!dir.exists()) return;
for (File file : Objects.requireNonNull(dir.listFiles())) {
if (file.isDirectory()) {
// 如果是目录,递归进入子目录继续扫描
scanDirectory(clazz, file, pkg + file.getName() + ".", list);
} else if (file.getName().endsWith(".class")) {
// 构建完整的类名(包含包名)
String className = pkg + file.getName().replace(".class", "");
try {
// 加载类
Class<?> tmp = Class.forName(className);
// 判断是否为目标类的实现类,并排除接口类型
if (clazz.isAssignableFrom(tmp) && !tmp.isInterface()) {
list.add(tmp);
}
} catch (Exception ignored) {
// 忽略加载失败的类
}
}
}
}
// 测试入口:演示如何使用ClassFinder查找AnnotationHandler接口的实现类
public static void main(String[] args) throws Exception {
// 查找AnnotationHandler接口的所有实现类
List<Class<?>> classes = getImplementationsOfMyService(AnnotationHandler.class);
System.out.println("找到以下实现类:");
for (Class<?> c : classes) {
System.out.println(c.getName());
}
}
}