[英]How to find all interfaces in class that extends other classes with other interfaces using reflection in java
[英]find all classes and interfaces a class extends or implements recursively
我想知道是否有一種簡單的方法可以確定 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 接口(例如,僅依賴於類對象的哈希碼)。
更新:將測試更改為使用哈希集。 德普。
該方法的以下實現執行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);
}
我測試了JFrame.class
,我得到了以下內容:
Set<Class<?>> 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<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));
}
從問題如何在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
包含這樣的功能,而是依賴於工具,例如JBoss Tools
,其中應該是允許遞歸類添加的功能。
在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));
}
}
測試代碼:
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 {}
}
輸出:
Test$Foo Test$Bar Test$I2 Test$I5 Test$I1 Test$I3 Test$I4
對@otamega 解決方案的一些建議減少:
這個不過濾對象(這將是不一致的)並使用一些重構和靜態導入來使代碼更具可讀性。
package com.stackoverflow.question22031207;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Stream.concat;
import static java.util.stream.Stream.of;
import static java.util.stream.Stream.ofNullable;
import java.util.Set;
import java.util.stream.Stream;
public class ClassUtil {
public static Set<Class<?>> getAllExtendedOrImplementedTypesRecursively(final Class<?> clazz) {
return walk(clazz).collect(toSet());
}
public static Stream<Class<?>> walk(final Class<?> clazz) {
final Class<?> superclass = clazz.getSuperclass();
final Class<?>[] interfaces = clazz.getInterfaces();
return concat(of(clazz), concat(ofNullable(superclass), stream(interfaces)).flatMap(ClassUtil::walk));
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.