局部類是在塊中定義的類,它是一對大括號之間的一組零個或多個語句,你一般會在方法體中找到定義的局部類。segmentfault
你能夠在任何塊中定義局部類(有關詳細信息,請參閱表達式、語句和塊),例如,你能夠在方法體、for
循環或if
子句中定義局部類。函數
如下示例LocalClassExample
驗證兩個電話號碼,它在validatePhoneNumber
方法中定義了局部類PhoneNumber
:code
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以外的全部字符來驗證電話號碼,以後,它會檢查電話號碼是否包含十位數字(北美電話號碼的長度),此示例打印如下內容:orm
First number is 1234567890 Second number is invalid
局部類能夠訪問其封閉類的成員,在前面的示例中,PhoneNumber
構造函數訪問成員LocalClassExample.regularExpression
。接口
此外,局部類能夠訪問局部變量,可是,局部類只能訪問聲明爲final
的局部變量,當局部類訪問封閉塊的局部變量或參數時,它會捕獲該變量或參數。例如,PhoneNumber
構造函數能夠訪問局部變量numberLength
,由於它被聲明爲final
;numberLength
是捕獲的變量。字符串
可是,從Java SE 8開始,局部類能夠訪問final
或有效final
的封閉塊的局部變量和參數,在初始化以後其值永遠不會改變的變量或參數其實是final
,例如,假設變量numberLength
未聲明爲final
,而且你在PhoneNumber
構造函數中添加賦值語句,以將有效電話號碼的長度更改成7位數:get
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
局部類中定義如下方法:io
public void printOriginalNumbers() { System.out.println("Original numbers are " + phoneNumber1 + " and " + phoneNumber2); }
printOriginalNumbers
方法訪問validatePhoneNumber
方法的參數phoneNumber1
和phoneNumber2
。編譯
在具備相同名稱的封閉範圍內的局部類遮蔽聲明中類型的聲明(例如變量),有關更多信息,請參閱遮蔽。
局部類與內部類相似,由於它們沒法定義或聲明任何靜態成員,靜態方法中的局部類,例如在靜態方法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(); }