在Java 14中引入了一个预览特性,即“模式匹配增强”(Pattern Matching for instanceof),这个特性在Java 16中继续作为预览特性,并在Java 17中成为正式特性。这个特性改进了instanceof的使用方式,允许在检查对象类型的同时进行类型转换,并且可以直接在条件表达式的结果中使用这个转换后的对象。

instanceof之前的写法

在Java 17之前,你需要使用传统的instanceof检查和显式的类型转换:

package com.morris.java17;

/**
 * java17之前版本instance of的使用
 */
public class InstanceOfOldDemo {
    public static void main(String[] args) {
        Object obj = "Hello, World!";

        if (obj instanceof String) {
            String str = (String) obj;
            System.out.println("Length: " + str.length());
        } else {
            System.out.println("Not a string");
        }
    }
}

instanceof模式匹配的使用

在Java 17及更高版本中,你可以这样使用instanceof模式匹配:

package com.morris.java17;

/**
 * instance of模式匹配的使用
 */
public class InstanceOfDemo {
    public static void main(String[] args) {
        Object o1 = "Hello, World!";

        if (o1 instanceof String str) {
            // 直接使用str变量,无需强制类型转换
            // str局部变量只能在这个if内使用,不能在else内使用
            System.out.println("Length: " + str.length());
        } else {
            System.out.println("Not a string");
        }

        // 判断一个对象是不是字符串并且长度大于2个字符,中间只能是&&,不能是&或者||
        Object o2 = "asr";
        if (o2 instanceof String str && str.length() > 2) {
            System.out.println("o2.length() > 2");
        } else {
            System.out.println("o2.length() <= 2");
        }

        Object o3 = "hello java";
        //这里做的是取反运算
        if (!(o3 instanceof String str)) {
            System.out.println("o3 not a String");
            // System.out.println(str);// 这里不能使用str
        } else {
            System.out.println(str);// 这里可以使用str
        }
    }
}

instanceof模式匹配只能在if、while、for等条件语句中使用。它不能用于switch语句(尽管Java 17引入了switch表达式的模式匹配,但这与instanceof模式匹配不同)。

使用instanceof模式匹配时,类型变量(如上面的str)的作用域仅限于if语句块内。

这个特性提高了代码的可读性和简洁性,避免了不必要的强制类型转换和可能的ClassCastException。

工作原理

反编译InstanceOfDemo的源码,可以发现编译后的代码是使用了强制类型转换。

package com.morris.java17;

public class InstanceOfDemo {
    public InstanceOfDemo() {
    }

    public static void main(String[] args) {
        Object o1 = "Hello, World!";
        String o2;
        if (o1 instanceof String) {
            o2 = (String)o1;
            System.out.println("Length: " + o2.length());
        } else {
            System.out.println("Not a string");
        }

        String o3;
        label22: {
            o2 = "asr";
            if (o2 instanceof String) {
                o3 = (String)o2;
                if (o3.length() > 2) {
                    System.out.println("o2.length() > 2");
                    break label22;
                }
            }

            System.out.println("o2.length() <= 2");
        }

        o3 = "hello java";
        if (o3 instanceof String) {
            String str = (String)o3;
            System.out.println(str);
        } else {
            System.out.println("o3 not a String");
        }

    }
}