迭代给定Class<?>
对象的所有超类/接口的最优雅方法是什么?我基本上在寻找递归getSuperclass()
和getInterfaces()
方法,收集整个类层次结构。
让我们假设我们的继承如下(其中Cn
是类,In
是接口):
I3
↗ ↖
C2 I1 I2
↖ ↖ ↗
C1 I0
↖ ↗
C0
它应该捕获上面显示的所有类。如果可能,迭代顺序应为breadth first,如下所示:
C0 -> C1 -> I0 -> C2 -> I1 -> I2 -> I3
是否有内置方法或图书馆可以创建Collection<Class<?>>
,Stream<Class<?>>
或Iterator<Class<?>>
?
任何帮助都是有意义的。
答案 0 :(得分:3)
此解决方案实现Iterator<Class<?>>
。如果你可以使用库,我建议你查看the accepted answer。
public static class HierarchyIterator implements Iterator<Class<?>> {
private Queue<Class<?>> remaining = new LinkedList<>();
private Set<Class<?>> visited = new LinkedHashSet<>();
public HierarchyIterator(Class<?> initial) {
append(initial);
}
private void append(Class<?> toAppend) {
if (toAppend != null && !visited.contains(toAppend)) {
remaining.add(toAppend);
visited.add(toAppend);
}
}
@Override
public boolean hasNext() {
return remaining.size() > 0;
}
@Override
public Class<?> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Class<?> polled = remaining.poll();
append(polled.getSuperclass());
for (Class<?> superInterface : polled.getInterfaces()) {
append(superInterface);
}
return polled;
}
}
如果您需要Collection<Class<?>>
,可以使用Google Guava:
public static Set<Class<?>> getClassHierarchy(Class<?> forClass) {
Set<Class<?>> result = new LinkedHashSet<>();
Iterators.addAll(result, new HierarchyIterator(forClass));
return result;
}
主叫:
System.out.println(getClassHierarchy(LinkedList.class));
产量
[class java.util.LinkedList, class java.util.AbstractSequentialList, interface java.util.List, interface java.util.Deque, interface java.lang.Cloneable, interface java.io.Serializable, class java.util.AbstractList, interface java.util.Collection, interface java.util.Queue, class java.util.AbstractCollection, interface java.lang.Iterable, class java.lang.Object]
答案 1 :(得分:3)
鉴于您似乎已经使用了Guava,这是使用Guava的Graph Traversal实用程序的解决方案。
public static Iterable<Class<?>> getClassHierarchy(Class<?> baseClass) {
return Traverser.forGraph(
(SuccessorsFunction<Class<?>>) node -> {
Class<?> superclass = node.getSuperclass();
List<Class<?>> interfaces = Arrays.asList(node.getInterfaces());
return superclass == null ? interfaces
: Iterables.concat(interfaces, Collections.singleton(superclass));
}
).breadthFirst(baseClass);
}
答案 2 :(得分:2)
我的问题或多或少像游戏一样,我注意到广度优先要求不是强制性的,所以这是我的解决方案。
forEach
样式。public class ClassIterator {
public void forEachSuperclasses(final Class<?> initialClass, final Consumer<Class<?>> action) {
generateStream(initialClass).distinct().forEach(action);
}
private Stream<Class<?>> generateStream(final Class<?> clazz) {
if (clazz == null) {
return Stream.empty();
}
return Stream.concat(
Stream.concat(Stream.of(clazz), generateStream(clazz.getSuperclass())),
Arrays.stream(clazz.getInterfaces()).flatMap(this::generateStream));
}
}
如何称呼它:
interface I3 {};
class C2 implements I3 {};
interface I1 extends I3 {};
interface I2 {};
class C1 extends C2 {};
interface I0 extends I0, I0 {};
class C0 extends C1 implements I0 {};
void testForEachSuperclasses() {
final ClassIterator iterator = new ClassIterator();
iterator.forEachSuperclasses(C1.class, System.out::println);
}
输出:
class com.example.classiterator.C0
class com.example.classiterator.C1
class com.example.classiterator.C2
class java.lang.Object
interface com.example.classiterator.I3
interface com.example.classiterator.I0
interface com.example.classiterator.I1
interface com.example.classiterator.I2
答案 3 :(得分:1)
这是一个横向的快速广度第一层次结构:
public class ClassHierarchy {
private Queue<Class<?>> queue;
//a collection of "visited" classes,
//which is also the result of the search
private Set<Class<?>> visited;
public Set<Class<?>> getClassHierarchy(Class<?> cls){
visited = new LinkedHashSet<>(); //initialize visited log
bfs(cls);
return visited;
}
//breadth first traverse on hierarchy
private void bfs(Class<?> cls) {
if(cls == null){ return; }
queue = new LinkedList<>(); //initialize queue
queue.add(cls);
while (! queue.isEmpty()) {
cls = queue.poll();
//loop over super classes
for(Class<?> nextClass : getSuperClasses(cls)){
if((nextClass != null) && visited.add(nextClass)) {
queue.add(nextClass); //add class to the queue
}
}
}
return;
}
private List<Class<?>> getSuperClasses(Class<?> cls) {
List<Class<?>> superCs = new ArrayList<>();
superCs.addAll(Arrays.asList(cls.getInterfaces()));
superCs.add(cls.getSuperclass());
return superCs;
}
private boolean isVisited(Class<?> cls) {
return !(visited.add(cls));
}
public static void main(String[] args) {
ClassHierarchy ch = new ClassHierarchy();
System.out.println(ch.getClassHierarchy(LinkedList.class));
}
}
(请仔细检查。我没有时间调试和改进。稍后会再看一下)
答案 4 :(得分:1)
这是另一个没有外部库的解决方案,但它仍然可以懒惰地运行并且每个类只访问一次:
public static Iterable<Class<?>> getClassHierarchy(Class<?> baseClass) {
return () -> new Iterator<Class<?>>() {
private Class<?> nextValue;
private Queue<Class<?>> remaining = new LinkedList<>(Collections.singleton(baseClass));
private Set<Class<?>> visited = new HashSet<>();
@Override
public boolean hasNext() {
while (nextValue == null && !remaining.isEmpty()) {
Optional.ofNullable(remaining.poll())
.ifPresent((Class<?> type) -> {
visited.add(type);
Stream.concat(
streamOptional(Optional.ofNullable(type.getSuperclass())),
Arrays.stream(type.getInterfaces())
).filter(visited::add)
.forEach(remaining::offer);
nextValue = type;
});
}
return nextValue != null;
}
private <T> Stream<T> streamOptional(final Optional<T> optional) {
return optional.map(Stream::of).orElse(Stream.empty());
}
@Override
public Class<?> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Class<?> value = this.nextValue;
this.nextValue = null;
return value;
}
};
}
注意:写这个很痛苦(在Java 8中),因为遗憾的是,没有Optional.stream()
方法,Stream.generate(supplier)
无法终止,所以我无法使用它。