Local Classes

局部类是在* block 中定义的类, block *是一组在平衡括号之间的零个或多个语句。通常,您会发现在方法主体中定义的局部类。

本节涵盖以下主题:

声明本地类

您可以在任何块内定义本地类(有关更多信息,请参见表达式,语句和块)。例如,您可以在方法主体,for循环或if子句中定义本地类。

以下示例LocalClassExample验证两个电话 Numbers。它在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");
    }
}

该示例通过首先从电话 Numbers 中删除除数字 0 到 9 之外的所有字符来验证电话 Numbers。此后,它检查电话 Numbers 是否恰好包含十个数字(北美电话 Numbers 的 Long 度)。本示例打印以下内容:

First number is 1234567890
Second number is invalid

访问封闭类的成员

本地类有权访问其所在类的成员。在前面的示例中,PhoneNumber构造函数访问成员LocalClassExample.regularExpression

此外,局部类可以访问局部变量。但是,局部类只能访问声明为 final 的局部变量。Authorities 部类访问封闭块的局部变量或参数时,它将“catch”该变量或参数。例如,PhoneNumber构造函数可以访问局部变量numberLength,因为它被声明为 final。 numberLengthcatch变量

但是,从 Java SE 8 开始,本地类可以访问 final 或* validally *的局部变量和封闭块的参数。变量或参数的值在初始化后从未更改,实际上是final的。例如,假设未将变量numberLength声明为 final,并在PhoneNumber构造函数中添加了突出显示的赋值语句,以将有效电话 Numbers 的 Long 度更改为 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

shade 和本地类

本地类中的类型声明(例如变量)会在封闭范围内的 shade 声明中具有相同的名称。有关更多信息,请参见Shadowing

本地class与内部class相似

局部类与内部类相似,因为它们无法定义或声明任何静态成员。静态方法中的本地类(例如,在静态方法validatePhoneNumber中定义的类PhoneNumber)只能引用封闭类的静态成员。例如,如果未将成员变量regularExpression定义为静态,则 Java 编译器将生成类似于“无法从静态上下文引用非静态变量regularExpression”的错误。

局部类是非静态的,因为它们可以访问封闭块的实例成员。因此,它们不能包含大多数静态声明。

您不能在块内声明interface;interface本质上是静态的。例如,以下代码摘录无法编译,因为interfaceHelloThere是在方法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();
    }

您不能在本地类中声明静态初始化器或成员interface。以下代码摘录无法编译,因为方法EnglishGoodbye.sayGoodbye被声明为static。当编译器遇到以下方法定义时,将生成类似于“只允许在常量变量声明中使用修饰符'static'的错误”:

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

本地类可以具有静态成员,前提是它们是常量变量。 (“常量变量*是原始类型或类型String的变量,该变量声明为 final 并使用编译时常量表达式进行初始化.编译时常量表达式通常是可以在编译时求值的字符串 或算术表达式.有关更多信息,请参见了解class成员。)由于静态成员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();
    }