当前位置: 首页 > news >正文

纯原生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());}}
}

相关文章:

  • 柔性超声耦合剂的选择与设计-可穿戴式柔性超声耦合剂面临的难题
  • [面试]SoC验证工程师面试常见问题(三)
  • 冯·诺依曼体系:现代计算机的底层逻辑与百年传承
  • 深度学习框架PyTorch——从入门到精通(YouTube系列 - 4)——使用PyTorch构建模型
  • 实现水平垂直居中的多种方法
  • 多模态RAG演进-MRAG1.0->MRAG2.0->MRAG3.0
  • 【验证技能】VIP项目大总结
  • C++派生类核心机制:类型转换与对象复制控制深度剖析
  • 通信协议记录仪-产品规格书
  • 如何让通义千问大模型支持结构化输出?
  • 使用xlwings将两张顺序错乱的表格进行数据核对
  • NVIDIA Omniverse在数字孪生中的算力消耗模型构建方法
  • C++ std::initializer_list 详解
  • 为美好的XCPC献上典题 ABC359 G - Sum of Tree Distance(根号分治)
  • 【AI面试准备】传统测试工程师Prompt Engineering转型指南
  • 在 Windows 中安装 Pynini 的记录
  • ECMAScript 2(ES2):标准化的微调与巩固
  • 每天一道算法题——推多米诺
  • leetcode 838. 推多米诺 中等
  • A2A Python 教程 - 综合指南
  • 申活观察|人潮涌动成常态,豫园为何常来常新?
  • 媒体:机票盲盒值不值得开?年轻人正用行为博弈的逻辑重构规则
  • 金科股份:因信披违规,公司及董事长、总裁、财务负责人等收到行政监管措施决定书
  • 思政课也精彩,“少年修齐讲堂”开讲《我的中国“芯”》
  • 小核酸药物企业瑞博生物递表港交所,去年亏损2.81亿元
  • 俄伏尔加格勒机场正式更名为斯大林格勒机场