Java 模式变量作用域

Ste*_*eve 10 java instanceof java-17

我正在阅读 Oracle 的官方文档来了解Java 17 中的模式变量范围。在以下示例中,该方法testScope1按照文档中的说明工作,但该方法testScope2给出了编译错误。我无法弄清楚为什么void该方法的返回类型会导致问题?

interface Vehicle{}
class Car implements Vehicle{}

class Pattern{
    public int testScope1(Vehicle v){
        if(!(v instanceof Car c)){
            return 1;
        }
        System.out.println(c.toString());  //WORKS FINE
        return 2; 
    }
    public void testScope2(Vehicle v){
        if(!(v instanceof Car c)){
                 
        }
        System.out.println(c.toString());  //COMPILE TIME ERROR: Cannot resolve symbol c
    }
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*etz 12

模式变量(在模式中声明的绑定变量)使用流敏感的作用域。与普通局部变量不同,普通局部变量在连续区域的范围内,模式变量在其声明模式明确分配的范围内

如果你有一个if声明:

if (x instanceof Foo(var v)) { 
    A;
}
else {
    B;
}
Run Code Online (Sandbox Code Playgroud)

thenv位于 for 的范围内A,但不在 for 的范围内B,因为我们不能保证v在到达 的情况下会明确地为 分配一个值B。如果我们使用明显的重构来反转我们的测试:

if (!(x instanceof Foo(var v))) { 
    B;
}
else {
    A;
}
Run Code Online (Sandbox Code Playgroud)

也是如此;v位于 范围内A,但不在范围内B这些规则与局部变量的明确赋值规则完全相同——“如果我到达这一点,这个值是否保证已被赋值”。

其他条件结构,例如短路&&||,也参与此范围界定。例如,以下内容是有效的:

if (x instanceof Foo(var v) && v != null) { 
    A;
}
Run Code Online (Sandbox Code Playgroud)

但以下不是:

if (x instanceof Foo(var v) || v != null) { 
    A;
}
Run Code Online (Sandbox Code Playgroud)

因为在后者中,v当我们到达该子句时,不能保证已被赋值v != null

这些规则甚至包含非本地控制流,例如异常。例如,如果我们有:

if (!(x instanceof Foo(var v)) { 
    System.out.println("Not a Foo");
}
B(v);
Run Code Online (Sandbox Code Playgroud)

这将是一个错误,因为v当我们到达 时,不能保证已经被分配了一个值B(v),但是如果if块突然完成:

if (!(x instanceof Foo(var v)) { 
    throw new NotFooException();
}
B(v);
Run Code Online (Sandbox Code Playgroud)

thenv位于 at 范围内B(v),因为我们可以保证,如果到达该点,v则已被赋值。

if这可能看起来很复杂,但实际上非常简单:鉴于您对、等结构的流程控制的了解throw,模式变量是否保证在给定点被赋值?如果是这样,那么它就在那时的范围内。


Kon*_*lph 7

想想如果不是v实例会发生什么:Car

\n
    \n
  • 在 中testScope1,该return 1;语句导致该方法退出。该方法的后续语句不会被执行。一切都很好。
  • \n
  • 其中testScope2\xe2\x80\x99s没有return,所以控制流达到c.toString()。但v\xe2\x80\x99t 不是一个Car,那么 \xe2\x80\xa6 是什么c?!它可以\xe2\x80\x99 不存在,因为它必须是某种类型,Car但\xe2\x80\x99 是一个反事实。这就是为什么您\xe2\x80\x99 收到错误\xe2\x80\x9c无法解析符号c\xe2\x80\x9d 的原因。
  • \n
\n