Java instanceof运算符

时间:2020-01-09 10:35:46  来源:igfitidea点击:

Java instanceof运算符可以确定给定的Java对象是给定类,超类还是接口的实例。如果我们有一个未知类型的对象,并且需要将其强制转换为已知类型以按预期使用它,这将非常有用。

Java instanceof运算符也称为类型比较运算符,因为它会将给定实例(对象)的类型与特定类型(类或者接口)进行比较。

Java instanceof示例

为了了解Java instanceof运算符的工作方式,让我们看一个简单的Java instanceof示例:

import java.util.HashMap;
import java.util.Map;

public class InstanceofExample {

    public static void main(String[] args) {
        Map<Object, Object> map = new HashMap();

        boolean mapIsObject = map instanceof Object;

        System.out.println(mapIsObject);
    }
}

请注意以下声明:

boolean mapIsObject = map instanceof Object;

如果map变量引用的对象是Object类或者Object类的任何子类的对象,则表达式map instanceof Object的计算结果为true。由于Java中的所有类均从Object继承,因此该表达式的值将为true

具有相同类的Instanceof

如前所述,如果将对象与该对象的确切类进行比较,则Java instanceof运算符的计算结果为true。这是一个Java instanceof示例,显示了对象与其确切类的比较:

HashMap<Object, Object> map = new HashMap();

boolean mapIsObject = map instanceof HashMap;

本示例的最后一行将把mapIsObject设置为true,因为map变量引用了HashMap类型的对象。

请注意,不是将引用对象的变量类型与引用对象的实际类型进行比较。这是另一个Java instanceof示例,它说明了这一点:

Map<Object, Object> map = new HashMap();

boolean mapIsObject = map instanceof HashMap;

注意,变量的类型现在是Map而不是HashMap。 Map不是HashMap的子类。因此,不能保证Map是HashMap的实例。但是,由于分配给map变量的实际对象是HashMap对象,因此示例的第二行仍将评估为true。

具有超类的Instanceof

如前所述,当将一个对象与该对象类型的超类进行比较时,Java instanceof运算符也将得出" true"。这是一个Java instanceof示例,它说明了这一点:

Map<Object, Object> map = new HashMap();

boolean mapIsObject = map instanceof Object;

由于HashMap是Object的子类,即使它不是直接的子类,表达式" map instanceof Object"的求值为true。

注意,比较的类型在对象层次结构的超类中在继承层次结构中的高低无关紧要。只要要比较的类型是继承层次结构中某个地方的超类,instanceof的评估结果就为true。

带接口的Instanceof

当将对象与接口而不是类进行比较时,Java instanceof运算符也可以工作。这是一个Java instanceof示例,显示了这一点:

HashMap<Object, Object> map = new HashMap();

boolean mapIsObject = map instanceof Map;

注意,即使map变量是HashMap类型,instanceof运算符也为表达式map map instanceof Map返回true,因为HashMap类实现了Map接口。如果变量的类型为Map,则也是如此,如以下示例所示:

Map<Object, Object> map = new HashMap();

boolean mapIsObject = map instanceof Map;

具有超级接口的Instanceof

当将对象与该对象的类或者该对象的超类实现的超接口进行比较时,Java instanceof运算符的计算结果也为true。这是一个Java instanceof示例,它说明了这一点:

SortedMap<Object, Object> map = new TreeMap();

boolean mapIsObject = map instanceof Map;

SortedMap接口扩展了Map接口。因此,地图是SortedMap的超级接口。 TreeMap类实现SortedMap,因此也间接实现Map接口。因此,示例的最后一行评估为" true"

Instanceof有null

当将" null"变量与任何类或者接口进行比较时,Java instanceof运算符始终将其评估为" false"。这是一个Java instanceof示例,它说明了null与一个类的比较:

Map<Object, Object> map = null;

boolean mapIsObject = map instanceof Map;

注意,即使map变量的类型是Map,并且将map变量与Map接口进行比较,比较的结果仍然是false。这是因为与目标类或者接口比较的不是引用类型,而是引用对象的实际类型。由于map变量的值为null,因此将其与Map map表达式中的Map接口进行比较。由于" null"不是Map的实例,因此表达式的计算结果为" false"。

Java编译器和instanceof运算符

有时,Java编译器可以在编译时就检测到instanceof表达式将始终评估为false。这是一个Java instanceof示例,它说明了这种情况:

String myString = "Hey";

if(myString instanceof Integer) {

}

由于Java String对象永远不能是Java Integer类的实例,因此Java编译器将捕获此错误并给我们一个错误。

使用instanceof向下转换

Java instanceof运算符最常见的用途之一是将超类型的对象下放为子类型。这是一个Java instanceof示例,它说明了向下转换的用例:

Map<Object, Object> map = new TreeMap;

//... more code that is left out

if(map instanceof SortedMap) {
  SortedMap sortedMap = (SortedMap) map;

  //do something with sortedMap.
}

如以下实例所示,向下转换也可以更"通用":

Object myObject = ... // get object from somewhere

if(myObject instanceof String) {
    String myString = (String) myObject;

} else if(myObject instance of Integer) {
    Integer myInteger = (Integer) myObject;

}

注意,引用对象的变量的类型为"对象"。这意味着所引用对象的实际类几乎可以是任何类(因为所有类都是Object的子类)。

具有模式匹配的instanceof

在Java 14中,Java instanceof运算符已通过模式匹配函数进行了扩展。该函数仍仅在Java 14中处于预览状态,但是很有可能它将保持这种形式或者类似形式。简而言之,在将对象与子类进行比较时,我们可以避免对象的显式贬低。这是一个Java instanceof示例,说明了模式匹配函数的instanceof:

Object myObject = ... // get object from somewhere

if(myObject instanceof String str) {
    System.out.println(str.substring(0,5));
}

请注意,if语句内instanceof表达式中的String类名之后的str变量。如果myObject变量引用的是String类型的对象,则str变量将绑定到该对象,并转换为String。因此,在if语句中,不再需要将myObject变量显式转换为String。

没有模式匹配instanceof函数,示例代码将如下所示:

Object myObject = ... // get object from somewhere

if(myObject instanceof String) {
    String str = (String) myObject;
    System.out.println(str.substring(0,5));
}

请注意if语句内第一行的显式强制转换。

如果instanceof表达式的计算结果为true,则实际上可以直接在同一表达式内使用downcast变量。这是一个实例实例,说明了这一点:

Object myObject = ... // get object from somewhere

if(myObject instanceof String str &&
   str.startsWith("Hello") ) {

    System.out.println(str + " starts with Hello");
}

注意,在声明变量的同一表达式中如何使用str变量。由于仅在表达式的右侧评估为" true"时才评估表达式的右侧,因此这不会导致在非String对象上调用" startsWith()"。