局部类
局部类是在块中定义的类,它是一对大括号之间的一组零个或多个语句,你通常会在方法体中找到定义的局部类。
声明局部类
你可以在任何块中定义局部类(有关详细信息,请参阅表达式、语句和块),例如,你可以在方法体、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
,因为它被声明为final
;numberLength
是捕获的变量。
但是,从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
方法的参数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();
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。