Java中如何检查一个类对象是否是另一个类对象的子类

255

我正在尝试使用Java的反射API并处理一些字段。现在我遇到了一个问题,如何识别我的字段类型。字符串很容易,只需执行myField.getType().equals(String.class)。对于其他非派生类也是如此。但是如何检查派生类呢?例如,LinkedList作为List的子类。我找不到任何isSubclassOf(...)extends(...)方法。我需要通过自己的方式遍历所有getSuperClass()并找到我的超类吗?


17
LinkedList 不是 List 的子类,而是 List 的一种实现方式 - T.J. Crowder
5
“Sub-type”可能是一个更好的术语。 - jpaugh
8个回答

482
你想要的是这个方法:
boolean isList = List.class.isAssignableFrom(myClass);
通常情况下,List(以上内容)应该被替换为superclassmyClass应该被替换为subclass
根据JavaDoc
确定由此Class对象表示的类或接口是与指定的Class参数表示的类或接口相同、超类或超接口。如果是,则返回true;否则返回false。如果此Class对象表示原始类型,则如果指定的Class参数恰好是此Class对象,则此方法返回true;否则返回false参考资料:
相关问题:

a) 在编译时检查一个对象是否是你所知道的一个类或接口(包括子类或实现类)的实例:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

示例:

assertTrue(Arrays.asList("a", "b", "c") instanceof List<?>);

b) 检查一个对象在运行时是否是某个类或接口(包括子类)的实例:

Class<?> typeOrInterface = // acquire class somehow
boolean isInstance = typeOrInterface.isInstance(someObject);

例子:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}

34
注意这个语法:SUPERCLASS.isAssignableFrom(SUBCLASS)。一开始这让我感到困惑,但考虑到命名,它其实很明显。 - codepleb
8
我同意。类似于SUPERCLASS.isExtendedBy(SUBCLASS)这样的写法会更容易理解。 - Sean Patrick Floyd
@SeanPatrickFloyd 实际上 isExtendedBy 是一个不好的名称,因为 CLASS.isAssignableFrom(CLASS) 会返回 true(因此 CLASS.isExtendedBy(CLASS) 也是如此)。这不是我所期望的。 - Qw3ry
@Qw3ry 是的,我假设这也是 API 作者所想的 :-) - Sean Patrick Floyd

30

另一个选项是使用 instanceof:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}

1
好的调用(+1)。然后还有两种机制的组合:Class.isInstance(object) http://download.oracle.com/javase/6/docs/api/java/lang/Class.html#isInstance%28java.lang.Object%29 - Sean Patrick Floyd
6
这意味着您要实例化那个Field。但我只想“查看”我的类及其字段,不想“试用”它们。 - craesh
我认为这种方法比“isAssignableFrom”更清晰、更简洁,特别是在需要检查对象的继承树时。 - cbuchart
请记住,instanceof 也适用于父类(在这种情况下是 Number)本身,而不仅仅是子类。 - lukaszrys

9

instanceof适用于实例,即对象。有时您想直接使用类进行操作。在这种情况下,您可以使用Class类的asSubclass方法。

以下是一些示例:

1)

    Class o=Object.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

这将会很顺利,因为JFrame是Object的子类。c将包含一个表示JFrame类的Class对象。

2)

    Class o=JButton.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

这将会引发一个java.lang.ClassCastException异常,因为JFrame不是JButton的子类。c将不会被初始化。
3)
    Class o=Serializable.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

这将会很顺利地进行,因为JFrame实现了java.io.Serializable接口。c将包含表示JFrame类的Class对象。当然需要包括所需的import。

7
这是我的解决方案:
protected boolean isTypeOf(String myClass, Class<?> superClass) {
    boolean isSubclassOf = false;
    try {
        Class<?> clazz = Class.forName(myClass);
        if (!clazz.equals(superClass)) {
            clazz = clazz.getSuperclass();
            isSubclassOf = isTypeOf(clazz.getName(), superClass);
        } else {
            isSubclassOf = true;
        }

    } catch(ClassNotFoundException e) {
        /* Ignore */
    }
    return isSubclassOf;
}

1
代码运行良好,但是如果遇到没有超类的java.lang.Object类,你可能需要在clazz = clazz.getSuperclass()后添加一个null检查。 - Jonas Pedersen

4

这是@schuttek答案的改进版本。它之所以更好,是因为它可以正确地返回原始类型的false (例如isSubclassOf(int.class, Object.class) => false),并且还可以正确地处理接口(例如isSubclassOf(HashMap.class, Map.class) => true)。

static public boolean isSubclassOf(final Class<?> clazz, final Class<?> possibleSuperClass)
{
    if (clazz == null || possibleSuperClass == null)
    {
        return false;
    }
    else if (clazz.equals(possibleSuperClass))
    {
        return true;
    }
    else
    {
        final boolean isSubclass = isSubclassOf(clazz.getSuperclass(), possibleSuperClass);

        if (!isSubclass && clazz.getInterfaces() != null)
        {
            for (final Class<?> inter : clazz.getInterfaces())
            {
                if (isSubclassOf(inter, possibleSuperClass))
                {
                    return true;
                }
            }
        }

        return isSubclass;
    }
}

4

一种递归方法,用于检查Class<?>是否是另一个Class<?>的子类...

@To Kra答案的改进版本:

protected boolean isSubclassOf(Class<?> clazz, Class<?> superClass) {
    if (superClass.equals(Object.class)) {
        // Every class is an Object.
        return true;
    }
    if (clazz.equals(superClass)) {
        return true;
    } else {
        clazz = clazz.getSuperclass();
        // every class is Object, but superClass is below Object
        if (clazz.equals(Object.class)) {
            // we've reached the top of the hierarchy, but superClass couldn't be found.
            return false;
        }
        // try the next level up the hierarchy.
        return isSubclassOf(clazz, superClass);
    }
}

2
最初的回答: //继承
    class A {
      int i = 10;
      public String getVal() {
        return "I'm 'A'";
      }
    }

    class B extends A {
      int j = 20;
      public String getVal() {
        return "I'm 'B'";
      }
    }

    class C extends B {
        int k = 30;
        public String getVal() {
          return "I'm 'C'";
        }
    }

//方法

    public static boolean isInheritedClass(Object parent, Object child) {
      if (parent == null || child == null) {
        return false;
      } else {
        return isInheritedClass(parent.getClass(), child.getClass());
      }
    }

    public static boolean isInheritedClass(Class<?> parent, Class<?> child) {
      if (parent == null || child == null) {
        return false;
      } else {
        if (parent.isAssignableFrom(child)) {
          // is child or same class
          return parent.isAssignableFrom(child.getSuperclass());
        } else {
          return false;
        }
      }
    }

最初的回答

// 测试代码

    System.out.println("isInheritedClass(new A(), new B()):" + isInheritedClass(new A(), new B()));
    System.out.println("isInheritedClass(new A(), new C()):" + isInheritedClass(new A(), new C()));
    System.out.println("isInheritedClass(new A(), new A()):" + isInheritedClass(new A(), new A()));
    System.out.println("isInheritedClass(new B(), new A()):" + isInheritedClass(new B(), new A()));


    System.out.println("isInheritedClass(A.class, B.class):" + isInheritedClass(A.class, B.class));
    System.out.println("isInheritedClass(A.class, C.class):" + isInheritedClass(A.class, C.class));
    System.out.println("isInheritedClass(A.class, A.class):" + isInheritedClass(A.class, A.class));
    System.out.println("isInheritedClass(B.class, A.class):" + isInheritedClass(B.class, A.class));

//Result

    isInheritedClass(new A(), new B()):true
    isInheritedClass(new A(), new C()):true
    isInheritedClass(new A(), new A()):false
    isInheritedClass(new B(), new A()):false
    isInheritedClass(A.class, B.class):true
    isInheritedClass(A.class, C.class):true
    isInheritedClass(A.class, A.class):false
    isInheritedClass(B.class, A.class):false

2
除了@To-kra答案之外,如果有人不喜欢递归:
    public static boolean isSubClassOf(Class<?> clazz, Class<?> superClass) {
        if(Object.class.equals(superClass)) {
            return true;
        }

        for(; !Object.class.equals(clazz); clazz = clazz.getSuperclass()) {
            if(clazz.getSuperclass().equals(superClass)) {
                return true;
            }
        }

        return false;
    }

注意:为了清晰易懂,本文档没有进行空值检查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接