簡體   English   中英

Java 模式變量 Scope

[英]Java Pattern Variable Scope

我正在通過 Oracle 的官方文檔來了解 Java 17 中的模式變量 scope 。在以下示例中,方法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
    }
}

放一個 else 語句。 只有在instanceof運算符產生true時才會創建模式變量。 否則沒有變量,因此編譯器錯誤。

  public void testScope2(Vehicle v){
      if(!(v instanceof Car c)){
             
      } else {
        System.out.println(c.toString());
      }
  }

編輯: testScope1方法不需要else語句,因為return語句已經存在。 如果v不是Car的實例, return語句確保控制永遠不會到達c.toString()

想想如果v不是Car實例會發生什么:

  • testScope1中, return 1; 語句導致方法退出。 不執行該方法的后續語句。 一切都很好。
  • testScope2中沒有return ,所以控制流到達c.toString() 但是v不是Car ,所以……什么是c ?,它不能存在,因為它必須是Car類型,但這是反事實的。 這就是您收到錯誤“無法解析符號c ”的原因。

對此花了更多的思考后,我有一個解釋:只有在該代碼段的 instanceof 明確為真時,才能訪問該變量。

在 testScope1 中,您無法在 if 語句中訪問c 但是由於 if 語句之后的代碼只有在 instanceof 為真時才會執行, c是可以訪問的。

在 testScope1 中,您無法在 if 語句中訪問c 但是由於 if 語句之后的代碼被執行,無論 instanceof 是真還是假c都無法訪問。 畢竟我們可能會遇到錯誤的情況,編譯器會相應地采取行動。

模式變量(模式中聲明的綁定變量)使用流敏感范圍 與在 scope 中用於連續區域的普通本地變量不同,模式變量在 scope中,它們將由它們的聲明模式明確分配

如果你有一個if語句:

if (x instanceof Foo(var v)) { 
    A;
}
else {
    B;
}

那么v在 scope 中是A ,但不是B ,因為我們不能保證在到達B的情況下v一定會被賦值。 如果我們使用明顯的重構來反轉我們的測試:

if (!(x instanceof Foo(var v))) { 
    B;
}
else {
    A;
}

也是如此; v在 scope 中A但不在B中。 規則與本地人的明確分配規則完全相同——“如果我達到這一點,這個值是否保證已經被分配了一個值。”

其他條件構造,例如短路&&|| ,也參與此范圍界定。 例如,以下是有效的:

if (x instanceof Foo(var v) && v != null) { 
    A;
}

但以下不是:

if (x instanceof Foo(var v) || v != null) { 
    A;
}

因為在后者中,當我們到達v != null子句時,不能保證v已經被賦值。

這些規則甚至包含非本地控制流,例如異常。 例如,如果我們有:

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

這將是一個錯誤,因為當我們到達B(v)時,不能保證v已經被賦值,但是如果if塊突然完成:

if (!(x instanceof Foo(var v)) { 
    throw new NotFooException();
}
B(v);

那么vB(v)處的 scope 中,因為我們保證如果我們到達那個點, v已經被分配了一個值。

這可能看起來很復雜,但實際上非常簡單:考慮到您對ifthrow等結構的流控制的了解,模式變量是否保證在給定點被賦值? 如果是這樣,那么它在 scope 中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM