Finding the nearest common superclass (or superinterface) of a collection of classes

后端 未结 6 1838
青春惊慌失措
青春惊慌失措 2020-12-08 14:23

Given a collection of classes, what\'s the best way to find the nearest common superclass?

E.g., given the following:

interface A {}
interface B {}
         


        
6条回答
  •  借酒劲吻你
    2020-12-08 15:12

    Full working solution to best of my knowledge

    • BFS of each class hierarchy going "upwards" - result into LinkedHashSet (preserve order + no duplicates)
    • Intersect each set with the next to find anything in common, again LinkedHashSet to preserve order
    • The remaining "ordered" set is the common ancestors, first in list is "nearest", last is furthest.
    • Empty list implies no ancestors (apart from object)

    Code

    private static Set> getClassesBfs(Class clazz) {
        Set> classes = new LinkedHashSet>();
        Set> nextLevel = new LinkedHashSet>();
        nextLevel.add(clazz);
        do {
            classes.addAll(nextLevel);
            Set> thisLevel = new LinkedHashSet>(nextLevel);
            nextLevel.clear();
            for (Class each : thisLevel) {
                Class superClass = each.getSuperclass();
                if (superClass != null && superClass != Object.class) {
                    nextLevel.add(superClass);
                }
                for (Class eachInt : each.getInterfaces()) {
                    nextLevel.add(eachInt);
                }
            }
        } while (!nextLevel.isEmpty());
        return classes;
    }
    
    private static List> commonSuperClass(Class... classes) {
        // start off with set from first hierarchy
        Set> rollingIntersect = new LinkedHashSet>(
                getClassesBfs(classes[0]));
        // intersect with next
        for (int i = 1; i < classes.length; i++) {
            rollingIntersect.retainAll(getClassesBfs(classes[i]));
        }
        return new LinkedList>(rollingIntersect);
    }
    

    Supporting methods and test

    private static void test(Class... classes) {
        System.out.println("Common ancestor for "
                + simpleClassList(Arrays.asList(classes)) + ", Result =>  "
                + simpleClassList(commonSuperClass(classes)));
    }
    
    private static String simpleClassList(Collection> classes) {
        StringBuilder builder = new StringBuilder();
        for (Class clazz : classes) {
            builder.append(clazz.getSimpleName());
            builder.append(",");
        }
        return builder.toString();
    }
    
    public static void main(String[] args) {
        test(A.class, AImpl.class);
        test(A.class, B.class, C.class);
        test(A.class, AB.class);
        test(AImpl.class, ABImpl.class);
        test(ABImpl.class, ABImpl2.class);
        test(AImpl.class, ABImpl.class, ABImpl2.class);
        test(ABImpl.class, ABImpl2.class, BCImpl.class);
        test(AImpl.class, ABImpl.class, ABImpl2.class, BCImpl.class);
        test(AB.class, ABImpl.class);
    }
    

    Output

    Common ancestor for A,AImpl,, Result =>  A,
    Common ancestor for A,B,C,, Result =>  
    Common ancestor for A,AB,, Result =>  A,
    Common ancestor for AImpl,ABImpl,, Result =>  A,
    Common ancestor for ABImpl,ABImpl2,, Result =>  A,B,
    Common ancestor for AImpl,ABImpl,ABImpl2,, Result =>  A,
    Common ancestor for ABImpl,ABImpl2,BCImpl,, Result =>  B,
    Common ancestor for AImpl,ABImpl,ABImpl2,BCImpl,, Result =>  
    Common ancestor for AB,ABImpl,, Result =>  AB,A,B,
    

提交回复
热议问题