java反射获取所有接口实现类

本文介绍了一种通过接口和反射技术来自动枚举并生成SQL语句,用于更新数据库中与枚举类型相关的映射值的方法。通过创建一个接口`IMetadataDict`,让所有相关枚举类实现该接口,然后使用`Reflections`库动态获取所有子类,遍历枚举值并获取其属性,以此简化数据库维护工作。

需求描述

项目业务前后端交互需要的一些特定值需要用枚举类型列举出来,并且每个枚举值对应的外部使用值不是固定的,
类似于 APPLE(“apple”,“苹果”) —> APLE 这样一个对应关系,而APLE是在数据库里配置的,不是固定的,在程序运行时从数据库加载到map里做映射,因为手动添加到数据库比较麻烦而且容易漏掉,于是想到利用接口加反射的方式,将所有的枚举类型列举出来,并根据一定规则生成sql语句插入数据库,然后直接去数据库手动修改映射值就可以了。

类继承关系为:IMetadataDict.class 为接口,各个枚举类实现这个接口,这样就不会将无关的枚举类也包含进去。

依赖及测试方法如下:

        <!-- 反射库 -->
        <!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.10.2</version>
        </dependency>
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Reflections reflections = new Reflections(IMetadataDict.class.getPackage().getName());
        Set<Class<? extends IMetadataDict>> set = reflections.getSubTypesOf(IMetadataDict.class);

        for (Class<? extends IMetadataDict> dict : set) {
            LOG.info("ClassName: {}", dict.getSimpleName());
            Method valueM = dict.getMethod("getValue");
            Method descM = dict.getMethod("getDesc");
            Method groupM = dict.getMethod("getGroupName");
            for (Object field : dict.getEnumConstants()) {
                String value = (String) valueM.invoke(field);
                String desc = (String) descM.invoke(field);
                String group = (String) groupM.invoke(field);
                LOG.info("group: {}, value: {}, desc: {}", group, value, desc);
            }
        }
    }
### Java反射机制获取所有实现了特定接口的类 Java反射机制允许程序在运行时自省或“检查”其结构,并可以在运行期间修改内部属性。对于获取实现了特定接口的所有类,可以利用`ServiceLoader`这一工具来加载服务提供者[^1]。 当使用`ServiceLoader`时,需确保目标实现类已注册至相应的配置文件中,通常位于`META-INF/services/`目录下,文件名为接口全限定名,内容则为各实现类的全限定名。以下是基于`ServiceLoader`的一个简单例子: ```java import java.util.ServiceLoader; public class InterfaceImplFinder { public static void main(String[] args) { ServiceLoader<YourInterface> loader = ServiceLoader.load(YourInterface.class); for (YourInterface impl : loader) { System.out.println(impl.getClass().getName()); } } } ``` 上述代码展示了如何遍历并打印出给定接口`YourInterface`的所有实现类名称。然而需要注意的是,此方式依赖于SPI(Service Provider Interfaces)机制,即需要开发者手动维护配置文件中的条目。 另一种不完全可靠但更通用的做法是扫描整个classpath下的所有类,尝试判断它们是否实现了指定接口。这涉及到复杂的字节码操作以及性能开销,在实际项目里应谨慎采用。一种简化版思路如下所示: ```java import java.io.File; import java.net.URL; import java.util.ArrayList; import java.lang.reflect.Modifier; public final class ClassScanner { private static String modifyPath(String path){ if(path.startsWith("/")) return path.substring(1); return path; } @SuppressWarnings("unchecked") public static ArrayList<Class<?>> getInterfaceImpls(Class<?> target,ClassLoader cl)throws Exception{ URL url=cl.getResource(""); File dir=new File(modifyPath(url.getPath())); ArrayList<Class<?>> classes=getClasses(dir,"",cl); ArrayList<Class<?>> result=new ArrayList<>(); for(Class<?> clazz:classes){ if(!clazz.isInterface()&&!Modifier.isAbstract(clazz.getModifiers())&&target.isAssignableFrom(clazz)){ result.add(clazz); } } return result; } // ... other methods to support the above function ... } ``` 这段代码片段定义了一个静态方法`getInterfaceImpls`用于返回实现了传入接口的所有具体类列表[^2]。请注意这种方法可能无法覆盖所有场景特别是面对模块化应用或者复杂部署环境的时候。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值