我们知道通过java反射可以获取到某个类的class对象,从而获取这个类中的所有重要信息,如获取到该类实现的所有接口和继承的父类,但是对于获取到该类的子类等信息则获取不到了,这就像我们可以知道古人,古人却不知道我们,向上可以获取,向下不行!那么通过什么手段可以向下获取呢?
实现原理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
public static ArrayList<Class<?>> getInterfaceImpls(Class<?> target) { ArrayList<Class<?>> subclassaes = Lists.newArrayList(); try { if (target.isInterface()) { @NotNull String basePackage = target.getClassLoader().getResource("").getPath(); File[] files = new File(basePackage).listFiles(); ArrayList<String> classpaths = Lists.newArrayList(); for (File file : files) { if (file.isDirectory()) { listPackages(file.getName(), classpaths); } } for (String classpath : classpaths) { Class<?> classObject = Class.forName(classpath); if (classObject.getSuperclass() == null) continue; Set<Class<?>> interfaces = new HashSet<>(Arrays.asList(classObject.getInterfaces())); if (interfaces.contains(target)) { subclasses.add(Class.forName(classObject.getName())); } } } else { throw new ParamException("Class对象不是一个interface"); } } catch (Throwable e) { e.printStackTrace(); } return subclasses; }
public static void listPackages(String basePackage, List<String> classes) { URL url = SophonUtils.class.getClassLoader() .getResource("./" + basePackage.replaceAll("\\.", "/")); File directory = new File(url.getFile()); for (File file : directory.listFiles()) { if (file.isDirectory()) { listPackages(basePackage + "." + file.getName(), classes); } else { String classpath = file.getName(); if (".class".equals(classpath.substring(classpath.length() - ".class".length()))) { classes.add(basePackage + "." + classpath.replaceAll(".class", "")); } } } }
|
代码演示:
使用方法非常简单,你只需要调用getInterfaceImpls()方法即可,listPackages()方法是个辅助。
1 2 3 4 5
|
ArrayList<Class<?>> subclass = getInterfaceImpls(SophonInit.class);
|
ps:值的注意的地方是,这个方法只能获取项目中自己定义的接口,不能获取到JDK或者是其他Jar包中的接口,因为这个工具的原理就是扫描编译后的classes目录