文档

Java™ 教程
隐藏目录
匿名类
路径:学习Java语言
课程:类和对象
章节:嵌套类

匿名类

匿名类使代码更简洁。它们允许你在声明和实例化类的同时进行。它们类似于局部类,但没有名称。如果你只需要使用局部类一次,就可以使用它们。

本节涵盖以下主题:

声明匿名类

局部类是类声明,而匿名类是表达式,这意味着你在另一个表达式中定义类。下面的示例HelloWorldAnonymousClasses在局部变量frenchGreetingspanishGreeting的初始化语句中使用了匿名类,但是在变量englishGreeting的初始化中使用了局部类::

public class HelloWorldAnonymousClasses {
  
    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }
  
    public void sayHello() {
        
        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }
      
        HelloWorld englishGreeting = new EnglishGreeting();
        
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };
        
        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }            
}

匿名类的语法

如前所述,匿名类是一个表达式。匿名类表达式的语法类似于调用构造函数,只是在代码块中包含一个类定义。

考虑实例化 frenchGreeting 对象的情况:

        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

匿名类表达式由以下部分组成:

由于匿名类定义是一个表达式,它必须是语句的一部分。在这个例子中,匿名类表达式是实例化 frenchGreeting 对象的语句的一部分。(这就解释了为什么在右括号之后有一个分号。)

访问封闭作用域的局部变量,以及声明和访问匿名类的成员

与局部类一样,匿名类可以捕获变量;它们可以访问封闭作用域的局部变量:

匿名类对于其成员也有与局部类相同的限制:

请注意,您可以在匿名类中声明以下内容:

但是,您不能在匿名类中声明构造函数。

匿名类的示例

匿名类通常在图形用户界面(GUI)应用程序中使用。

考虑JavaFX示例 HelloWorld.java(来自 Hello World, JavaFX Style一节,来自 JavaFX入门指南)。此示例创建一个包含一个Say 'Hello World'按钮的框架。匿名类表达式已突出显示:

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class HelloWorld extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
 
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });
        
        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }
}

在此示例中,方法调用btn.setOnAction指定选择Say 'Hello World'按钮时发生的情况。此方法需要一个EventHandler<ActionEvent>类型的对象。 EventHandler<ActionEvent>接口只包含一个方法handle。示例中使用匿名类表达式而不是使用新类实现此方法。请注意,此表达式是传递给btn.setOnAction方法的参数。

由于EventHandler<ActionEvent>接口只包含一个方法,因此可以使用lambda表达式而不是匿名类表达式。有关更多信息,请参见Lambda表达式一节。

匿名类非常适合实现包含两个或多个方法的接口。下面的JavaFX示例来自自定义UI控件一节。突出显示的代码创建一个只接受数值的文本字段。它通过使用匿名类重写继承自TextInputControl类的replaceTextreplaceSelection方法来重新定义TextField类的默认实现。

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class CustomTextFieldSample extends Application {
    
    final static Label label = new Label();
 
    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 300, 150);
        stage.setScene(scene);
        stage.setTitle("文本框示例");
 
        GridPane grid = new GridPane();
        grid.setPadding(new Insets(10, 10, 10, 10));
        grid.setVgap(5);
        grid.setHgap(5);
 
        scene.setRoot(grid);
        final Label dollar = new Label("$");
        GridPane.setConstraints(dollar, 0, 0);
        grid.getChildren().add(dollar);
        
        final TextField sum = new TextField() {
            @Override
            public void replaceText(int start, int end, String text) {
                if (!text.matches("[a-z, A-Z]")) {
                    super.replaceText(start, end, text);                     
                }
                label.setText("请输入数值");
            }
 
            @Override
            public void replaceSelection(String text) {
                if (!text.matches("[a-z, A-Z]")) {
                    super.replaceSelection(text);
                }
            }
        };
 
        sum.setPromptText("输入总数");
        sum.setPrefColumnCount(10);
        GridPane.setConstraints(sum, 1, 0);
        grid.getChildren().add(sum);
        
        Button submit = new Button("提交");
        GridPane.setConstraints(submit, 2, 0);
        grid.getChildren().add(submit);
        
        submit.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                label.setText(null);
            }
        });
        
        GridPane.setConstraints(label, 0, 1);
        GridPane.setColumnSpan(label, 3);
        grid.getChildren().add(label);
        
        scene.setRoot(grid);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}

上一页: 本地类
下一页: Lambda 表达式