Degree of relation between Java object and classes/interfaces?
Is there some way through the standard library or some already existing library to determine the degree of relation between two classes/interfaces in Java?
Let's say I have an object and a list of classes/interfaces. Now I basically want to know the one class of that list, that has the shortest inheritance-tree path to this object.
I already looked through the java.lang.reflect package and Class, but couldn't really find anything that would allow easy access to information like this. Is that perhaps already part of a开发者_运维技巧nother library?
Reflection will let you get the parent class for any given class, so you can extract enough information to build yourself an inheritance tree, which you can then use to answer your question. I can't think of any built-in mechanism which will let you do that any more elegantly.
I don't know anything ready to use.
I would use Reflection to discover the relationships.
The hard part is the shortest-path.
You have to define what exactly you want :
- For example, do you search superclasses first and then interfaces ?
- What do you decide when several have the same length of path ?
Use alphabetical order ?
Use the order of discovery (which is random) ? ...
Then, look for these classes or interfaces in that order, starting with the current class, then it's parent class (and possibly implemented interfaces), and so on...
this helps a bit. Not sure how to get the shortest path.
I couldn't help but find this a fun-sounding project. Here is prototype code that gives you the information you need. This code just attempts to calculate all of the possible inheritance paths from a given class to another. You could use this to get all of the paths from your source object to all of the possible classes you're interested in. As mentioned in other comments you may have to make a call about whether your prefer paths that use interfaces or not, but hopefully this code is helpful to you.
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);
}
}
}
This code should get you close. As others have stated, you may run into issues with interfaces though since the inheritance depth could easily be the same. You'll also need to add some null checking etc.
In this example FooBar3 extends FooBar2 extends 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;
}
精彩评论