【问题标题】:How to check if a subclass is an instance of a class at runtime? [duplicate]如何在运行时检查子类是否是类的实例? [复制]
【发布时间】:2011-01-25 12:02:38
【问题描述】:

在一个 android 应用程序测试套件中,我有一个这样的类,其中 B 是一个视图:

public class A extends B {
... etc...
}

现在我有一个视图对象列表,其中可能包含A 对象,但在这种情况下,我只关心它们是否是B 的子类或“实例”。我想做类似的事情:

ArrayList<View> viewList = getViews();
Iterator<View> iterator = viewList.iterator();
while (iterator.hasNext() && viewList != null) {
    View view = iterator.next();
    if (view.getClass().isInstance(B.class)) {
        // this is an instance of B
    }
}

问题是当if 遇到A 对象时,它不会评估为“B 的实例”。有什么办法可以做isSubclassOf 什么的吗?

【问题讨论】:

  • 来自Effective C++,作者Scott Meyers:“任何时候你发现自己在编写格式为”的代码,如果对象是T1类型,那么做一些事情,但如果它是T2类型,那么做其他事情” 打自己一巴掌。你能不能不使用重写的方法?或者像访问者模式这样的东西。
  • 这是一个测试用例,所以代码实际上不在生产应用程序中,它是为了测试以确保使用正确的类:)
  • 如果 viewList 数组为空,那么您的程序会崩溃,即使签入也无济于事。
  • 类不变断言就是这样做的一种情况。 (正如 iamamused 所说)

标签: java subclass instanceof


【解决方案1】:

您必须仔细阅读此方法的 API。有时你很容易感到困惑。

是:

if (B.class.isInstance(view))

API 说:确定 指定的对象 (参数) 是否与 this Class 表示的对象分配兼容 (您正在调用该方法的类对象)

或:

if (B.class.isAssignableFrom(view.getClass()))

API 说:确定此 Class object 表示的类或接口是否与 指定 Class 表示的类或接口相同,或者是其超类或超接口参数

或(不考虑反射和推荐的):

if (view instanceof B)

【讨论】:

  • +1 表示 if(查看 instanceof B)。简单而有效。
  • 请注意,instanceof 由于被擦除,因此不适用于泛型。
  • @Qix 感谢您的信息。擦除是不止一个身体部位的痛苦,但没有泛型的工作更糟糕。
  • 说实话,我什至不认为 Java 的泛型是真正的泛型。 Java 的泛型只是类型安全(或更重要的是强制执行)的语法糖。它们纯粹是编译时间,我认为大多数来自 C++ 和随后的模板的人将很难掌握擦除的概念。
【解决方案2】:
if(view instanceof B)

如果 view 是 B 的实例或 A 的子类(或 B 的任何子类),这将返回 true。

【讨论】:

  • 我想提一下,必须在当前的 .java 文件中导入 B 才能使其工作。 Eclipse 会将该行标记为有错误,但不会提供任何有用的解决方案(在意识到我还没有导入类文件之前浪费了近一个小时尝试不同的语法。)对于任何想知道的人来说,正确的语法是 ((instance name) instanceof (班级名称))。词类没有出现在其中的任何地方。
【解决方案3】:

也许我错过了什么,但这还不够:

if (view instanceof B) {
    // this view is an instance of B
}

【讨论】:

    【解决方案4】:

    Class.isAssignableFrom() - 也适用于接口。如果您不想这样做,则必须致电getSuperclass() 并进行测试,直到到达Object

    【讨论】:

      【解决方案5】:

      反过来说:B.class.isInstance(view)

      【讨论】:

        【解决方案6】:

        如果有检查SQLRecoverableException vs SQLException之类的多态,可以这样处理。

        try {
            // sth may throw exception
            ....
        } catch (Exception e) {
            if(SQLException.class.isAssignableFrom(e.getCause().getClass()))
            {
                // do sth
                System.out.println("SQLException occurs!");
            }
        }
        

        简单地说,

        ChildClass child= new ChildClass();
        if(ParentClass.class.isAssignableFrom(child.getClass()))
        {
            // do sth
            ...
        }
        

        【讨论】:

        • 如果您没有充分的理由,请不要执行诸如捕获异常和检查异常类之类的操作。改为:} catch (SQLException e) { } catch (Exception e){ }
        • 不推荐使用 try ... catch 测试某些东西
        【解决方案7】:

        我从来没有真正使用过这个,但是试试view.getClass().getGenericSuperclass()

        【讨论】:

        • 该方法的名称和文档都错误。这对解决问题没有帮助,因为 A 和 B 都没有任何泛型。
        猜你喜欢
        • 2019-01-08
        • 1970-01-01
        • 2012-06-30
        • 1970-01-01
        • 2013-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-26
        相关资源
        最近更新 更多