Documentation

The Java™ Tutorials
Hide TOC
Local Classes局部类
Trail: Learning the Java Language
Lesson: Classes and Objects
Section: Nested Classes

Local Classes局部类

Local classes are classes that are defined in a block, which is a group of zero or more statements between balanced braces.局部类是在块中定义的类,块是平衡大括号之间的一组零或多个语句。You typically find local classes defined in the body of a method.通常可以在方法体中找到定义的局部类。

This section covers the following topics:本节涵盖以下主题:

Declaring Local Classes声明局部类

You can define a local class inside any block (see Expressions, Statements, and Blocks for more information).可以在任何块内定义局部类(有关详细信息,请参阅表达式、语句和块)。For example, you can define a local class in a method body, a for loop, or an if clause.例如,可以在方法体、for循环或if子句中定义局部类。

The following example, LocalClassExample, validates two phone numbers.下面的示例LocalClassExample验证两个电话号码。It defines the local class PhoneNumber in the method validatePhoneNumber:它在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");
    }
}

The example validates a phone number by first removing all characters from the phone number except the digits 0 through 9.该示例通过首先删除电话号码中除数字0到9之外的所有字符来验证电话号码。After, it checks whether the phone number contains exactly ten digits (the length of a phone number in North America).之后,它会检查电话号码是否正好包含十位数字(北美电话号码的长度)。This example prints the following:此示例打印以下内容:

First number is 1234567890
Second number is invalid

Accessing Members of an Enclosing Class访问封闭类的成员

A local class has access to the members of its enclosing class.局部类可以访问其封闭类的成员。In the previous example, the PhoneNumber constructor accesses the member LocalClassExample.regularExpression.在上一个示例中,PhoneNumber构造函数访问成员LocalClassExample.regularExpression

In addition, a local class has access to local variables.此外,局部类可以访问局部变量。However, a local class can only access local variables that are declared final.但是,局部类只能访问声明为final的局部变量。When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter.当局部类访问封闭块的局部变量或参数时,它将捕获该变量或参数。For example, the PhoneNumber constructor can access the local variable numberLength because it is declared final; numberLength is a captured variable.例如,PhoneNumber构造函数可以访问局部变量numberLength,因为它被声明为finalnumberLength是一个捕获的变量。

However, starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final.然而,从JavaSE8开始,局部类可以访问封闭块的最终或有效最终的局部变量和参数。A variable or parameter whose value is never changed after it is initialized is effectively final.一个变量或参数的值在初始化后永远不会改变,它实际上是最终的。For example, suppose that the variable numberLength is not declared final, and you add the highlighted assignment statement in the PhoneNumber constructor to change the length of a valid phone number to 7 digits:例如,假设变量numberLength未声明为final,并在PhoneNumber构造函数中添加突出显示的赋值语句,以将有效电话号码的长度更改为7位:

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

Because of this assignment statement, the variable numberLength is not effectively final anymore.由于这个赋值语句,变量numberLength不再是有效的最终。As a result, the Java compiler generates an error message similar to "local variables referenced from an inner class must be final or effectively final" where the inner class PhoneNumber tries to access the numberLength variable:因此,Java编译器会生成类似于“从内部类引用的局部变量必须是最终或有效最终”的错误消息,其中内部类PhoneNumber尝试访问numberLength变量:

if (currentNumber.length() == numberLength)

Starting in Java SE 8, if you declare the local class in a method, it can access the method's parameters.从Java SE 8开始,如果在方法中声明局部类,它可以访问该方法的参数。For example, you can define the following method in the PhoneNumber local class:例如,您可以在PhoneNumber局部类中定义以下方法:

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

The method printOriginalNumbers accesses the parameters phoneNumber1 and phoneNumber2 of the method validatePhoneNumber.printOriginalNumbers方法访问validatePhoneNumber方法的参数phoneNumber1phoneNumber2

Shadowing and Local Classes阴影与局部类

Declarations of a type (such as a variable) in a local class shadow declarations in the enclosing scope that have the same name.局部类中的类型声明(如变量)会在封闭范围中隐藏具有相同名称的声明。See Shadowing for more information.有关详细信息,请参阅阴影

Local Classes Are Similar To Inner Classes局部类类似于内部类

Local classes are similar to inner classes because they cannot define or declare any static members.局部类与内部类类似,因为它们不能定义或声明任何静态成员。Local classes in static methods, such as the class PhoneNumber, which is defined in the static method validatePhoneNumber, can only refer to static members of the enclosing class.静态方法中的局部类,例如在静态方法validatePhoneNumber中定义的类PhoneNumber,只能引用封闭类的静态成员。For example, if you do not define the member variable regularExpression as static, then the Java compiler generates an error similar to "non-static variable regularExpression cannot be referenced from a static context."例如,如果未将成员变量regularpression定义为静态,则Java编译器将生成类似于“无法从静态上下文引用非静态变量regularExpression”的错误。

Local classes are non-static because they have access to instance members of the enclosing block.局部类是非静态的,因为它们可以访问封闭块的实例成员。Consequently, they cannot contain most kinds of static declarations.因此,它们不能包含大多数类型的静态声明。

You cannot declare an interface inside a block; interfaces are inherently static.不能在块内声明接口;接口本质上是静态的。For example, the following code excerpt does not compile because the interface HelloThere is defined inside the body of the method greetInEnglish:例如,由于接口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();
    }

You cannot declare static initializers or member interfaces in a local class.不能在局部类中声明静态初始值设定项或成员接口。The following code excerpt does not compile because the method EnglishGoodbye.sayGoodbye is declared static.以下代码摘录未编译,因为方法EnglishGoodbye.sayGoodbye声明为静态。The compiler generates an error similar to "modifier 'static' is only allowed in constant variable declaration" when it encounters this method definition:当编译器遇到此方法定义时,会生成类似于“修饰符'static'仅允许在常量变量声明中使用”的错误:

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

A local class can have static members provided that they are constant variables.局部类可以有静态成员,只要它们是常量变量。(A constant variable is a variable of primitive type or type String that is declared final and initialized with a compile-time constant expression.常量变量是基元类型或String类型的变量,它被声明为final并用编译时常量表达式初始化。A compile-time constant expression is typically a string or an arithmetic expression that can be evaluated at compile time.编译时常量表达式通常是可以在编译时计算的字符串或算术表达式。See Understanding Class Members for more information.)有关详细信息,请参阅了解类成员。)The following code excerpt compiles because the static member EnglishGoodbye.farewell is a constant variable:编译以下代码摘录是因为静态成员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();
    }

Previous page: Inner Class Example
Next page: Anonymous Classes