Java™ 教程(區域性類)

博弈發表於2019-01-19

區域性類

區域性類是在塊中定義的類,它是一對大括號之間的一組零個或多個語句,你通常會在方法體中找到定義的區域性類。

宣告區域性類

你可以在任何塊中定義區域性類(有關詳細資訊,請參閱表示式、語句和塊),例如,你可以在方法體、for迴圈或if子句中定義區域性類。

以下示例LocalClassExample驗證兩個電話號碼,它在validatePhoneNumber方法中定義了區域性類PhoneNumber

public class LocalClassExample {
  
    static String regularExpression = "[^0-9]";
  
    public static void validatePhoneNumber(
        String phoneNumber1, String phoneNumber2) {
      
        final int numberLength = 10;
        
        // Valid in JDK 8 and later:
       
        // int numberLength = 10;
       
        class PhoneNumber {
            
            String formattedPhoneNumber = null;

            PhoneNumber(String phoneNumber){
                // numberLength = 7;
                String currentNumber = phoneNumber.replaceAll(
                  regularExpression, "");
                if (currentNumber.length() == numberLength)
                    formattedPhoneNumber = currentNumber;
                else
                    formattedPhoneNumber = null;
            }

            public String getNumber() {
                return formattedPhoneNumber;
            }
            
            // Valid in JDK 8 and later:

//            public void printOriginalNumbers() {
//                System.out.println("Original numbers are " + phoneNumber1 +
//                    " and " + phoneNumber2);
//            }
        }

        PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);
        PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);
        
        // Valid in JDK 8 and later:

//        myNumber1.printOriginalNumbers();

        if (myNumber1.getNumber() == null) 
            System.out.println("First number is invalid");
        else
            System.out.println("First number is " + myNumber1.getNumber());
        if (myNumber2.getNumber() == null)
            System.out.println("Second number is invalid");
        else
            System.out.println("Second number is " + myNumber2.getNumber());

    }

    public static void main(String... args) {
        validatePhoneNumber("123-456-7890", "456-7890");
    }
}

該示例通過首先移除電話號碼中除數字0到9之外的所有字元來驗證電話號碼,之後,它會檢查電話號碼是否包含十位數字(北美電話號碼的長度),此示例列印以下內容:

First number is 1234567890
Second number is invalid

訪問封閉類的成員

區域性類可以訪問其封閉類的成員,在前面的示例中,PhoneNumber建構函式訪問成員LocalClassExample.regularExpression

此外,區域性類可以訪問區域性變數,但是,區域性類只能訪問宣告為final的區域性變數,當區域性類訪問封閉塊的區域性變數或引數時,它會捕獲該變數或引數。例如,PhoneNumber建構函式可以訪問區域性變數numberLength,因為它被宣告為finalnumberLength是捕獲的變數。

但是,從Java SE 8開始,區域性類可以訪問final或有效final的封閉塊的區域性變數和引數,在初始化之後其值永遠不會改變的變數或引數實際上是final,例如,假設變數numberLength未宣告為final,並且你在PhoneNumber建構函式中新增賦值語句,以將有效電話號碼的長度更改為7位數:

PhoneNumber(String phoneNumber) {
    numberLength = 7;
    String currentNumber = phoneNumber.replaceAll(
        regularExpression, "");
    if (currentNumber.length() == numberLength)
        formattedPhoneNumber = currentNumber;
    else
        formattedPhoneNumber = null;
}

由於這個賦值語句,變數numberLength不再是final,因此,Java編譯器生成類似於“從內部類引用的區域性變數必須是final或者有效的final”的錯誤訊息,其中內部類PhoneNumber嘗試訪問numberLength變數:

if (currentNumber.length() == numberLength)

從Java SE 8開始,如果在方法中宣告區域性類,它可以訪問方法的引數,例如,你可以在PhoneNumber區域性類中定義以下方法:

public void printOriginalNumbers() {
    System.out.println("Original numbers are " + phoneNumber1 +
        " and " + phoneNumber2);
}

printOriginalNumbers方法訪問validatePhoneNumber方法的引數phoneNumber1phoneNumber2

遮蔽和區域性類

在具有相同名稱的封閉範圍內的區域性類遮蔽宣告中型別的宣告(例如變數),有關更多資訊,請參閱遮蔽。

區域性類與內部類相似

區域性類與內部類類似,因為它們無法定義或宣告任何靜態成員,靜態方法中的區域性類,例如在靜態方法validatePhoneNumber中定義的類PhoneNumber,只能引用封閉類的靜態成員。例如,如果未將成員變數regularExpression定義為static,則Java編譯器會生成類似於“非靜態變數regularExpression無法從靜態上下文引用”的錯誤。

區域性類是非靜態的,因為它們可以訪問封閉塊的例項成員,因此,它們不能包含大多數型別的靜態宣告。

你不能在一個塊內宣告一個介面;介面本質上是靜態的,例如,以下程式碼片段不會編譯,因為介面HelloThere是在方法greetInEnglish的主體內定義的:

public void greetInEnglish() {
        interface HelloThere {
           public void greet();
        }
        class EnglishHelloThere implements HelloThere {
            public void greet() {
                System.out.println("Hello " + name);
            }
        }
        HelloThere myGreeting = new EnglishHelloThere();
        myGreeting.greet();
    }

你不能在區域性類中宣告靜態初始化或成員介面,以下程式碼片段無法編譯,因為方法EnglishGoodbye.sayGoodbye被宣告為static,當遇到此方法定義時,編譯器會生成類似於“修飾符`static`的錯誤,只允許在常量變數宣告中使用”:

public void sayGoodbyeInEnglish() {
        class EnglishGoodbye {
            public static void sayGoodbye() {
                System.out.println("Bye bye");
            }
        }
        EnglishGoodbye.sayGoodbye();
    }

區域性類可以具有靜態成員,前提是它們是常量變數(常量變數是原始型別或型別String的變數,它被宣告為final並使用編譯時常量表示式進行初始化,編譯時常量表示式通常是可在編譯時計算的字串或算術表示式,有關更多資訊,請參閱瞭解類成員),以下程式碼片段編譯,因為靜態成員EnglishGoodbye.farewell是一個常量變數:

public void sayGoodbyeInEnglish() {
        class EnglishGoodbye {
            public static final String farewell = "Bye bye";
            public void sayGoodbye() {
                System.out.println(farewell);
            }
        }
        EnglishGoodbye myEnglishGoodbye = new EnglishGoodbye();
        myEnglishGoodbye.sayGoodbye();
    }

上一篇:巢狀類

下一篇:匿名類

相關文章