Java 查找一个类递归扩展或实现的所有类和接口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22031207/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:09:50  来源:igfitidea点击:

find all classes and interfaces a class extends or implements recursively

javaclassjboss-arquillian

提问by coderatchet

I was wondering if there was an easy way of determining the complete list of Types that a Java class extends or implements recursively?

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

for instance:

例如:

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));
    }
}

Think Arquillian ShrinkWrap creation helper.

想想 Arquillian ShrinkWrap 创建助手。

UPDATE:due to the Class object not implementing Comparable> I also need to find a way of creating a Set (or similar class) without implementing the Comparable interface (for instance, solely relying on the hashcode of the class object).

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

UPDATE:changed the test to use hashset. derp.

更新:将测试更改为使用哈希集。德普。

采纳答案by higuaro

The following implementation of the method does what the OP requires, it traverses the inheritance hierarchy for every class and interface:

该方法的以下实现满足 OP 的要求,它遍历每个类和接口的继承层次结构:

public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(Class<?> clazz) {
    List<Class<?>> 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<Class<?>>(res);
}    

I tested with JFrame.classand I got the following:

我测试了JFrame.class,我得到了以下信息:

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

Output:

输出:

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

UPDATE:For the OP's test case it prints:

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

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

回答by TA Nguyen

There is a ClassUtils in the Apache Common Langthat have the 2 methods you want. .getAllSuperClasses() and .getAllInterfaces().

Apache Common Lang中有一个 ClassUtils,其中包含您想要的 2 种方法。.getAllSuperClasses() 和 .getAllInterfaces()。

回答by chrylis -cautiouslyoptimistic-

The key you want is in the Class#getSuperclass()method:

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

public static Set<Class<?>> stuff(Class<?> target) {
    Set<Class<?>> classesInterfaces = new HashSet<>();
    classesInterfaces.add(target);
    classesInterfaces.addAll(Arrays.asList(target.getInterfaces());

    Class<?> superClass = target.getSuperclass();
    if(superClass != null)
        classesInterfaces.addAll(stuff(superClass));
}

回答by Miguel Jiménez

From the question How do you find all subclasses of a given class in Java?, thisanswer might be helpful:

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

Using the class PojoClassImpl.javayou can get the super class by calling method getSuperClass(). I think that is sufficient for you to write a recursive method.

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

回答by stinepike

If I got your question right, you want to find all the superclasses (class and interface) of a specific class. If so you can check the following solution

如果我问对了你的问题,你想找到特定类的所有超类(类和接口)。如果是这样,您可以检查以下解决方案

to find the superclasses

找到超类

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

to find the interfaces

找到接口

        C = getClass();
        for(Class adf: C.getInterfaces()){

              System.out.println(adf.getSimpleName());
        }

回答by ravi.patel

It's very easy, in case your class is Foo then your code will be like this,

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

public void getClassDetails() {

    Class klass = Foo.class;
    Class<?> superKlass = klass.getSuperClass();
    Class[] interfaces = klass.getInterfaces();
}

回答by mmatloka

I have once implemented similiar mechanism using asmon some ShrinkWrap branch https://github.com/mmatloka/shrinkwrap/commit/39d5c3aa63a9bb85e6d7b68782879ca10cca273b. The issue is sometimes class might use object which is an interface implementation not mentioned in other file so it still can fail during deployment.

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

From what I know some time ago official position was rather not to include such feature inside of the ShrinkWrap, but rather rely on tooling e.g. JBoss Tools, where should be a feature allowing for recursive class additions.

据我所知,前一段时间官方立场是相当不包括的这种特征内部ShrinkWrap,而是依赖于工具例如JBoss Tools,在这里应该是允许递归类添加的功能。

回答by otamega

In Java8

在 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<Class<?>> getAllExtendedOrImplementedTypesRecursively(final Class<?> clazz) {
        return walk(clazz)
                .filter(Predicate.isEqual(java.lang.Object.class).negate())
                .collect(Collectors.toSet());
    }

    public static Stream<Class<?>> 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));
    }
}

Test Code:

测试代码:

import java.util.Set;

class Test {
    public static void main(String[] args) {
        final Set<Class<?>> 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 {}
}

Output:

输出:

Test$Foo
Test$Bar
Test$I2
Test$I5
Test$I1
Test$I3
Test$I4