Java 汇编指令instanceof 的规则是什么意思?

What is the meaning of the rules for Java assembly instruction instanceof?

在Java字节码汇编指令层面下钻到运算符instanceof时,对应一条Java汇编指令instanceof。但是我看规则习惯了

determine whether an objectref that is not null is an instance of the resolved type:

第二条规则告诉:

If S is an interface type, then:

  • If T is a class type, then T must be Object.
  • If T is an interface type, then T must be the same interface as S or a superinterface of S.

这让我很困惑。 “S是接口类型”是否意味着S的引用类型是接口类型?如果是这样,第一条规则“如果 T 是 class 类型,则 T 必须是对象”不能成立。例如,

CharSequence charSequence = new StringBuilder("test");
System.out.println(charSequence instanceof StringBuilder);
System.out.println(charSequence instanceof String);

上面代码中的第二行将打印 true,而上面的第三行将打印 false。所以我怀疑我的理解可能是错误的,谁能帮忙解释一下上面规则的意思?

您有权感到困惑,因为这些规则的编写方式,令人困惑。

对于 objectref不可能 具有接口类型,因为每个实例化对象都有一个实际的非抽象类型,也许实现一个接口。这甚至适用于为 lambda 表达式生成的实例,这些实例具有实现功能接口的未指定(匿名)类型。

所以乍一看,这些规则的这一部分似乎没有任何意义。但考虑全文:

The following rules are used to determine whether an objectref that is not null is an instance of the resolved type: If S is the class of the object referred to by objectref and T is the resolved class, array, or interface type, instanceof determines whether objectref is an instance of T as follows:

  • If S is an ordinary (nonarray) class, then:
    • If T is a class type, then S must be the same class as T, or S must be a subclass of T;
    • If T is an interface type, then S must implement interface T.
  • If S is an interface type, then:
    • If T is a class type, then T must be Object.
    • If T is an interface type, then T must be the same interface as S or a superinterface of S.
  • If S is a class representing the array type SC[], that is, an array of components of type SC, then:
    • If T is a class type, then T must be Object.
    • If T is an interface type, then T must be one of the interfaces implemented by arrays (JLS §4.10.3).
    • If T is an array type TC[], that is, an array of components of type TC, then one of the following must be true:
      • TC and SC are the same primitive type.
      • TC and SC are reference types, and type SC can be cast to TC by these run-time rules.

由于objectref引用的实际对象不可能有接口类型,所以只适用另外两条;它的类型是“普通(非数组)class”或数组类型。在后一种情况下,最后一句话很有趣,因为它指的是引用的规则作为一个整体,应用于 TS 的组件类型(如果两者都是引用数组)类型。组件类型可能是接口类型。

因此您可以使用接口类型的实际数组实例测试这些规则,并检查其他数组类型:

Object o = new Collection[0]; // SC is Collection
System.out.println(o instanceof Object[]); // TC is class type Object -> true
System.out.println(o instanceof String[]); // TC is class type other than Object -> false
System.out.println(o instanceof Collection[]); // TC == SC -> true
System.out.println(o instanceof Iterable[]); // TC is super interface of SC -> true
System.out.println(o instanceof List[]); // TC is not super interface SC -> false

它认为,如果在可能适用的数组特殊情况下描述接口情况,那将不会那么混乱。另一方面,这三种情况都遵循了一般的正式赋值规则,因此以这种形式更容易识别。