查找类以递归方式扩展或实现的所有类和接口

我想知道是否有一种简单的方法来确定Java类以递归方式扩展或实现的完整类型列表?

例如:

class Foo extends Bar implements I1, I2 {...} class Bar implements I3 {...} interface I1 extends I4, I5 {...} interface I2 {...} interface I3 {...} interface I4 {...} interface I5 {...} class ClassUtil { public static Set<Class> getAllExtendedOrImplementedTypesRecursively(Class clazz){ ??? } } import static org.junit.Assert.*; public class ClassUtilTest { @Test public void shouldEqualClasses(){ Set<Class> types = ClassUtil.getAllExtendedOrImplementedTypesRecursively(Foo.class); Set<Class> checklist = new HashSet(); checklist.add(Foo.class); checklist.add(Bar.class); checklist.add(I1.class); checklist.add(I2.class); checklist.add(I3.class); checklist.add(I4.class); checklist.add(I5.class); assertTrue(checklist.containsAll(types)); assertTrue(types.containsAll(checklist)); } } 

想想Arquillian ShrinkWrap创作助手。

更新:由于Class对象没有实现Comparable>我还需要找到一种创建Set(或类似类)而不实现Comparable接口的方法(例如,仅依赖于类对象的hashcode)。

更新:更改测试以使用hashset。 DERP。

该方法的以下实现执行OP所需的操作,它遍历每个类和接口的inheritance层次结构:

 public static Set> getAllExtendedOrImplementedTypesRecursively(Class clazz) { List> res = new ArrayList<>(); do { res.add(clazz); // First, add all the interfaces implemented by this class Class[] interfaces = clazz.getInterfaces(); if (interfaces.length > 0) { res.addAll(Arrays.asList(interfaces)); for (Class interfaze : interfaces) { res.addAll(getAllExtendedOrImplementedTypesRecursively(interfaze)); } } // Add the super class Class superClass = clazz.getSuperclass(); // Interfaces does not have java,lang.Object as superclass, they have null, so break the cycle and return if (superClass == null) { break; } // Now inspect the superclass clazz = superClass; } while (!"java.lang.Object".equals(clazz.getCanonicalName())); return new HashSet>(res); } 

我用JFrame.class测试JFrame.class ,我得到了以下内容:

 Set> classes = getAllExtendedOrImplementedTypesRecursively(JFrame.class); for (Class clazz : classes) { System.out.println(clazz.getName()); } 

输出:

 java.awt.Container java.awt.Frame javax.swing.JFrame javax.swing.TransferHandler$HasGetTransferHandler java.awt.Window javax.accessibility.Accessible javax.swing.RootPaneContainer java.awt.Component javax.swing.WindowConstants java.io.Serializable java.awt.MenuContainer java.awt.image.ImageObserver 

更新:对于OP的测试用例,它打印:

 test.I5 test.Bar test.I2 test.I1 test.Foo test.I3 test.I4 

Apache Common Lang中有一个ClassUtils,它有你想要的2种方法。 .getAllSuperClasses()和.getAllInterfaces()。

你想要的关键是在Class#getSuperclass()方法中:

 public static Set> stuff(Class target) { Set> classesInterfaces = new HashSet<>(); classesInterfaces.add(target); classesInterfaces.addAll(Arrays.asList(target.getInterfaces()); Class superClass = target.getSuperclass(); if(superClass != null) classesInterfaces.addAll(stuff(superClass)); } 

从问题如何在Java中找到给定类的所有子类? , 这个答案可能会有所帮助:

使用类PojoClassImpl.java,您可以通过调用方法getSuperClass()来获取超类。 我认为这足以让你编写一个递归方法。

如果我的问题是正确的,那么您希望找到特定类的所有超类(类和接口)。 如果是这样,您可以检查以下解决方案

找到超类

  Class C = getClass(); while (C != null) { System.out.println(C.getSimpleName()); C = C.getSuperclass(); } 

找到接口

  C = getClass(); for(Class adf: C.getInterfaces()){ System.out.println(adf.getSimpleName()); } 

这很容易,如果你的课程是Foo,那么你的代码将是这样的,

 public void getClassDetails() { Class klass = Foo.class; Class superKlass = klass.getSuperClass(); Class[] interfaces = klass.getInterfaces(); } 

我曾经在一些ShrinkWrap分支上使用asm实现了类似的机制https://github.com/mmatloka/shrinkwrap/commit/39d5c3aa63a9bb85e6d7b68782879ca10cca273b 。 问题是有时类可能使用对象,这是其他文件中未提及的接口实现,因此在部署期间仍然可能失败。

从我ShrinkWrap所知的官方位置ShrinkWrap ,不是在ShrinkWrap包含这样的function,而是依赖于工具,例如JBoss Tools ,其中应该是允许递归类添加的function。

在Java8中

 import java.util.Arrays; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; public class ClassUtil { public static Set> getAllExtendedOrImplementedTypesRecursively(final Class clazz) { return walk(clazz) .filter(Predicate.isEqual(java.lang.Object.class).negate()) .collect(Collectors.toSet()); } public static Stream> walk(final Class c) { return Stream.concat(Stream.of(c), Stream.concat( Optional.ofNullable(c.getSuperclass()).map(Stream::of).orElseGet(Stream::empty), Arrays.stream(c.getInterfaces()) ).flatMap(ClassUtil::walk)); } } 

测试代码:

 import java.util.Set; class Test { public static void main(String[] args) { final Set> set = ClassUtil.getAllExtendedOrImplementedTypesRecursively(Foo.class); set.stream().map(Class::getName).forEach(System.out::println); } class Foo extends Bar implements I1, I2 {} class Bar implements I3 {} interface I1 extends I4, I5 {} interface I2 {} interface I3 {} interface I4 {} interface I5 {} } 

输出:

测试$美孚
测试$酒吧
测试$ I2
测试$ I5
测试$ I1
测试$ I3
测试$ I4