【Java】Java 16中不再需要进行instanceof后的类型转换

首先

当使用instanceof时,有时我们会像下面这样进行强制类型转换。

if (obj instanceof String) {
    
    String s = (String) obj;
    
    // do anything
}

听说从Java 16开始不需要强制类型转换了。

 

如果你知道那个的话,就不需要读以下内容了。

就会变成这样

这被称为 instanceof 模式匹配。

最初的代码可以写成如下的样子。

if (obj instanceof String s) {
    
    // do anything
}

在这一行代码中,完成了以下操作。

    1. 如果obj是String类型,则将其转换为String类型

 

    将其赋值给变量s(在这里我们称s为模式变量)

因此,在后续的处理中,可以使用s进行各种处理。

模式变量的范围

模式变量的作用域如下所述。

只有当编译器可以推断出模式一定匹配并且变量已经被赋值时,模式变量才处于作用域内。

只有在编译器能够确定模式匹配并给变量赋值的情况下,模式变量才会进入作用域。

换句话说,模式变量的作用范围只在变量被赋值并具有意义时才存在。(这被称为流程作用域,大概是这个意思)

例如,可以如下所示。

public class Sample {

	void foo(Object obj) {

        // (1)
		if (obj instanceof String a) {

            // objがString型の場合、パターン変数aのスコープ内
		}

        // (2)
		if (obj instanceof Boolean a) {
    		
            // objがBoolean型の場合、パターン変数aのスコープ内
		}

        // パターン変数aのスコープ外
	}

在这段代码中,使用了相同的模式变量a在(1)和(2)处。
如果使用instanceof匹配了类型,变量a将在各自的if代码块中有作用域,否则变量a就没有作用域。

使用!后作用域相反。

public class Sample {

	void foo(Object obj) {
        
        if (!(obj instanceof String s)) {
        
            // objはString型ではなくsのスコープ外
        } else {

            // objはString型でsのスコープ内
        }
        
        // sのスコープ外
    }
}

再给一个样本吧!

public class Sample {

	void foo(Object obj) {
        
        if (!(obj instanceof String s)) {
            
            throw new IllegalArgumentException("Must be a string");
        }

        // sのスコープ
        var s = "hoge"; // コンパイルエラー
    }
}

在 `if` 语句结束后,保证了作用域变量 `s` 是 `String` 类型,所以 `if` 语句之后成为了 `s` 的作用域。
因此,如果试图重新声明 `s`,将会出现编译错误。

此外,即使会引发异常,如果不抛出异常,则无法保证 s 是 String 类型,因此可以将其声明为超出作用域。

顺便提一句

可以通过变量屏蔽(在重叠的作用域中使用相同名称的变量,使得低级作用域的变量覆盖高级作用域的变量)来操作字段变量。

class Example {

	String s;

	void test(Object o) {

		if (o instanceof String s) {

			System.out.println(s); // shadowing
			s = s + "\n"; 
		}

		System.out.println(s);
	}
}

当使用以下代码运行时,将显示hoge,null。

public class Main {

	public static void main(String[] args) {

		Example e = new Example();
		e.test("hoge");
	}
}

用途

例如,我认为在Java 16之前,有时候需要使用equals来编写如下的代码。

public class Foo {

	int i;

	@Override
	public boolean equals(Object obj) {

		if (!(obj instanceof Foo)) {

			return false;
		}
        
        // instanceofで確認した後にキャスト
		Foo other = (Foo) obj;

		if (other.i != this.i) {

			return false;
		}

		return true;
	}
}

这是一个equals方法,如果Foo对象的变量i相等,则返回true。

这样↓可以写成↑。

public class Foo {

	int i;

	@Override
	public boolean equals(Object obj) {

		return (obj instanceof Foo other) && other.i == this.i;
	}
}

最後

如果有任何错误或需要补充的地方,请大家提出指正,感激不尽。

广告
将在 10 秒后关闭
bannerAds