Степень связи между объектом Java и классами / интерфейсами? - PullRequest
3 голосов
/ 05 января 2010

Есть ли какой-нибудь способ через стандартную библиотеку или уже существующую библиотеку определить степень связи между двумя классами / интерфейсами в Java?

Допустим, у меня есть объект и список классов / интерфейсов. Теперь я в основном хочу знать один класс этого списка, который имеет кратчайший путь дерева наследования к этому объекту.

Я уже просмотрел пакет java.lang.reflect и класс, но не смог найти ничего, что обеспечивало бы легкий доступ к такой информации. Возможно, это уже часть другой библиотеки?

Ответы [ 5 ]

3 голосов
/ 05 января 2010

Reflection позволит вам получить родительский класс для любого данного класса, так что вы сможете извлечь достаточно информации, чтобы построить себе дерево наследования, которое вы затем сможете использовать для ответа на свой вопрос. Я не могу придумать какой-либо встроенный механизм, который позволит вам делать это более элегантно.

1 голос
/ 05 января 2010

Я не мог не найти этот забавный проект. Вот код прототипа, который дает вам необходимую информацию. Этот код просто пытается вычислить все возможные пути наследования от одного класса к другому. Вы можете использовать это, чтобы получить все пути от вашего исходного объекта ко всем возможным классам, которые вас интересуют. Как упоминалось в других комментариях, вам, возможно, придется позвонить по поводу того, предпочитаете ли вы пути, использующие интерфейсы, или нет, но надеюсь, этот код будет полезен для вас.

public class InheritenceDepth {

/**
 * Obtains a list of all the possible inheritance paths from the given targetClass
 * to the specified potentialAncestorClass.  If the targetClass does not extend or implement
 * the potentialAncestorClass the return list will be empty.
 */
public static List<InheritancePath> classInheritancePaths(Class<?> targetClass, Class<?> potentialAncestorClass){
    List<InheritancePath> returnList = new ArrayList<InheritancePath>();
    if(potentialAncestorClass.isAssignableFrom(targetClass)){

        if(potentialAncestorClass.equals(targetClass)){
            returnList.add(new InheritancePath(potentialAncestorClass));
        }

        if(targetClass.getSuperclass() != null){
            // try superclass
            List<InheritancePath> pathsFromSuperClass = 
                classInheritancePaths(targetClass.getSuperclass(), potentialAncestorClass);
            if(!pathsFromSuperClass.isEmpty()){
                for(InheritancePath path : pathsFromSuperClass){
                    path.add(targetClass);
                    returnList.add(path);
                }
            }
        }

        // try interfaces
        for(Class<?> interf : targetClass.getInterfaces()){
            List<InheritancePath> pathsFromInterface = 
                classInheritancePaths(interf, potentialAncestorClass);
            if(!pathsFromInterface.isEmpty()){
                for(InheritancePath path : pathsFromInterface){
                    path.add(targetClass);
                    returnList.add(path);
                }
            }
        }
    }
    return returnList;
}

/**
 * Represents the path from a base class to a superclass
 */
public static final class InheritancePath implements Iterable<Class<?>>{
    private List<Class<?>> path = new ArrayList<Class<?>>();
    public InheritancePath(Class<?> root){
        path.add(root);
    }

    void add(Class<?> pathElement){
        path.add(0, pathElement);
    }

    public Iterator<Class<?>> iterator(){
        return path.iterator();
    }

    public int depth(){
        return path.size();
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < path.size(); i++){
            sb.append(path.get(i).getName());
            if(i < path.size() - 1){
                sb.append(" -> ");
            }
        }
        return sb.toString();
    }
}

public static void main(String[] args) {
    List<InheritancePath> paths = classInheritancePaths(ConcurrentLinkedQueue.class, Collection.class);

    for(InheritancePath path : paths){
        System.out.println(path);
    }
}

}

1 голос
/ 05 января 2010

Я не знаю ничего готового к использованию.

Я бы использовал Reflection, чтобы обнаружить отношения.

Самая трудная часть - самый короткий путь.

  • Вы должны определить, что именно вы хотите:

    • Например, вы сначала ищете суперклассы, а затем интерфейсы?
    • Что вы решите, когда несколько имеют одинаковую длину пути?
      Использовать алфавитный порядок?
      Использовать порядок обнаружения (который случайный)? ...
  • Затем ищите эти классы или интерфейсы в том порядке, начиная с текущего класса, затем его родительского класса (и, возможно, реализованных интерфейсов) и т. Д.

1 голос
/ 05 января 2010

это немного помогает. Не уверен, как получить кратчайший путь.

0 голосов
/ 05 января 2010

Этот код должен приблизить вас. Как уже говорили другие, вы можете столкнуться с проблемами с интерфейсами, хотя глубина наследования может легко быть одинаковой. Вам также нужно будет добавить проверку нуля и т. Д.

В этом примере FooBar3 расширяет FooBar2 расширяет FooBar.

public static void main(String[] args) {
    List<Class<?>> l = new ArrayList<Class<?>>() {{
        add(FooBar2.class);
        add(FooBar.class);
    } };
    System.out.println(getClosestParent(new FooBar3(), l));
 }

public static Class getClosestParent(Object o, List<Class<?>> classes) {
    List<Class<?>> related = getRelated(o, classes);
    Collections.sort(related, new Comparator<Class<?>>() {
        public int compare(Class<?> o1, Class<?> o2) {
            if (o1.isAssignableFrom(o2)) {
                return -1;
            } else if (o2.isAssignableFrom(o1)) {
                return 1;
            }
            return 0;
        }
    });
    return related.get(0);
}

public static List<Class<?>> getRelated(Object o, List<Class<?>> classes) {
    List<Class<?>> filtered = new ArrayList<Class<?>>();
    for (Class<?> aClass : classes) {
        if (aClass.isAssignableFrom(o.getClass())) {
            filtered.add(aClass);
        }

    }
    return filtered;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...