本地类就是指的一种在一个块中定义的类,包在一对花括弧里含0个或者多个表达式组。典型的,你能在方法主体里找到它。
声明一个本地类
你可以在一个块里声明本地类。举个例子:你可以在方法体里定义本地类,一个 for 循环或者 一个 if 语句里。
以下例子,LocalClassExample.java, 校验2个电话号码。它定义了本地类PhoneNumber 在 方法 validPhoneNumber。
public class LocalClassExample {
static String regularExpression = "[^0-9]";
public static void validatePhoneNumber (String phoneNumber1, String phoneNumber2) {
final int numberLength = 10;
// Valid in JDK8 and later:
// int numberLength = 10;
class PhoneNumber {
String formattedPhoneNumber = null;
PhoneNumber(String phoneNumber) {
String currentNmuber = phoneNumber.replaceAll(regularExpression, "");
if (currentNumber.length() == numberLength) {
formattedNumber = currentNumber;
} else {
formattedNumber = null;
}
}
public String getNumber() {
return formattedNumber ;
}
public void printOriginalNumbers() {
System.out.println("Original numbers are " + phoneNumber1 + " and " + phoneNumber2);
}
}
PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);
PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);
myNumber1.printOriginalNumber();
}
public staic void main(String... args) {
validatePhoneNumber("123-456-7890", "456-7890");
}
}
示例通过移除所有除了0到9的字符校验了电话号码。之后,它检查电话号码是否精确的包含了10个数字。示例的打印如下:
First number is 1234567890
Second number is invalid
访问包围类的成员
本地类可以访问它包围类的成员。在前个示例,PhoneNumber 的构造函数就访问了成员 LocalClassExample.regularExpression.
此外,本地类还可以访问本地变量。然而,本地类只能访问被声明为final的本地变量。当一个本地类访问一个本地变量或者包围类参数的时候,它捕获该变量或参数。举例,PhoneNumber构造函数能访问变量 numberLength因为它被声明为final;numberLength就是一个捕获变量。
然而,从JAVA SE 8开始,本地类能访问包含类里为final或effectively final的本地变量和参数。变量或者参数的值在初始化之后不会再修改就称为effectively 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不再是effectively final。结果就是,JAVA编译器会在内部类PhoneNumber尝试去访问numberLength变量的地方抛出错误,类似于“local variables referenced from an inner class must be final or effectively final”:
if (currentNumber.length() == numberLength)
从JAVA SE8开始,如果你声明了在方法中声明本地类,那么它可以访问方法的参数。举例,你能在PhoneNumber本地类里定义以下方法:
public void printOriginNumbers() {
System.out.println("Original number are " + phoneNumber1 + " and " + phoneNumber2);
}
方法printOriginalNumbers访问了方法alidatePhoneNumber参数phoneNumber1 和 phoneNumber2。
遮蔽效应和本地类
在本地类中的类型声明会遮蔽包围类有同样名字的声明。
本地类类似于内部类
本地类类似于内部类因为他们都不能声明或定义任何静态成员。静态方法中的本地类,比如定义在静态方法validatePhoneNumber的类PhoneNumber,只能引用包围类的静态成员。举例,假如你没有定义成员变量 regularExpression为static,那么JAVA编译器就会抛出 “non-static variable regularExpression cannot be referenced from a static context”.
本地类是non-static因为他们都能访问包围类实例的成员。后果就是,他们不能包含有静态声明。
你不能在一个块中定义一个接口;接口天生就是静态的。举例,接下来的代码片段不能被编译因为接口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();
myGreeeting.greet();
}
你不能在一个本地类里声明静态初始块或接口成员。以下代码片段无法编译因为方法EnglishGoodbye.sayGoodbye被声明为了static。当编译器碰到了这个方法定义,就会抛出一个错误”modifier ‘static’ is only allowed in constant variable declaration“
public void sayGoodbyeInEnglish() {
class EnglishGoodbye {
public static void sayGoodbye() {
System.out.print("Bye bye");
}
}
EnglishGoodbye.sayGoodbye();
}
本地类可以拥有被认为是常量的静态成员。以下代码片段能被编译因为静态成员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();
}