资讯专栏INFORMATION COLUMN

Java™ 教程(匿名类)

xietao3 / 3159人阅读

匿名类

匿名类可以使你代码更简洁,它们使你能够同时声明和实例化一个类,它们就像局部类,除了它们没有名称,如果你只需要使用局部类一次,请使用它们。

声明匿名类

虽然局部类是类声明,但匿名类是表达式,这意味着你在另一个表达式中定义该类,以下示例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);
     }
};

匿名类表达式包含以下内容:

new运算符。

要实现的接口的名称或要继承的类,在此示例中,匿名类正在实现接口HelloWorld

包含构造函数参数的圆括号,就像普通的类实例创建表达式一样,注意:实现接口时,没有构造函数,因此你使用一对空括号,如本例所示。

类声明体,更具体地说,类体中,方法声明是允许的,但语句不是。

因为匿名类定义是表达式,所以它必须是语句的一部分,在此示例中,匿名类表达式是实例化frenchGreeting对象的语句的一部分(这解释了为什么在闭合花括号后有一个分号)。

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

与局部类一样,匿名类可以捕获变量,它们对封闭范围的局部变量具有相同的访问权限:

匿名类可以访问其封闭类的成员。

匿名类无法访问其封闭范围中未声明为final或者实际为final的局部变量。

与嵌套类一样,匿名类中的类型(例如变量)的声明会影响封闭范围中具有相同名称的任何其他声明,有关更多信息,请参阅遮蔽。

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

你不能在匿名类中声明静态初始化或成员接口。

匿名类可以具有静态成员,前提是它们是常量变量。

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

字段

额外的方法(即使他们没有实现超类型的任何方法)

实例初始化

局部类

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

匿名类的示例

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

考虑JavaFX示例HelloWorld.java(来自Hello World的部分,来自JavaFX入门的JavaFX样式),此示例创建一个包含Say "Hello World"按钮的frame:

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() {
 
            @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类型的对象,EventHandler接口只包含一个方法handle。该示例使用匿名类表达式,而不是使用新类实现此方法,请注意,此表达式是传递给btn.setOnAction方法的参数。

因为EventHandler接口只包含一个方法,所以可以使用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("Text Field Sample");
 
        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("Enter a numeric value");
            }
 
            @Override
            public void replaceSelection(String text) {
                if (!text.matches("[a-z, A-Z]")) {
                    super.replaceSelection(text);
                }
            }
        };
 
        sum.setPromptText("Enter the total");
        sum.setPrefColumnCount(10);
        GridPane.setConstraints(sum, 1, 0);
        grid.getChildren().add(sum);
        
        Button submit = new Button("Submit");
        GridPane.setConstraints(submit, 2, 0);
        grid.getChildren().add(submit);
        
        submit.setOnAction(new EventHandler() {
            @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表达式

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72441.html

相关文章

  • Java教程(Lambda表达式)

    Lambda表达式 匿名类的一个问题是,如果匿名类的实现非常简单,例如只包含一个方法的接口,那么匿名类的语法可能看起来不实用且不清楚,在这些情况下,你通常会尝试将功能作为参数传递给另一个方法,例如当有人单击按钮时应采取的操作,Lambda表达式使你可以执行此操作,将功能视为方法参数,或将代码视为数据。 上一节匿名类向你展示了如何在不给它命名的情况下实现基类,虽然这通常比命名类更简洁,但对于只有一个...

    lansheng228 评论0 收藏0
  • Java教程(嵌套

    嵌套类 Java编程语言允许你在另一个类中定义类,这样的类称为嵌套类,如下所示: class OuterClass { ... class NestedClass { ... } } 术语:嵌套类分为两类:静态和非静态,声明为static的嵌套类称为静态嵌套类,非静态嵌套类称为内部类。 class OuterClass { ... stati...

    Cheng_Gang 评论0 收藏0
  • Java 8 简明教程

    摘要:简明教程原文译者黄小非来源简明教程并没有没落,人们很快就会发现这一点欢迎阅读我编写的介绍。编译器会自动地选择合适的构造函数来匹配函数的签名,并选择正确的构造函数形式。 Java 8 简明教程 原文:Java 8 Tutorial 译者:ImportNew.com - 黄小非 来源:Java 8简明教程 ‍ Java并没有没落,人们很快就会发现这一点 欢迎阅读我编写的Java ...

    testHs 评论0 收藏0
  • Android内存泄漏定位、分析、解决全方案

    摘要:如果这个静态变量在生命周期结束后没有清空,就导致内存泄漏。因此造成内存泄露。注册没取消造成的内存泄露这种的内存泄露比纯的内存泄漏还要严重,因为其他一些程序可能引用系统的程序的对象比如注册机制。 原文链接 更多教程 为什么会发生内存泄漏 内存空间使用完毕之后未回收, 会导致内存泄漏。有人会问:Java不是有垃圾自动回收机制么?不幸的是,在Java中仍存在很多容易导致内存泄漏的逻辑(...

    yiliang 评论0 收藏0

发表评论

0条评论

xietao3

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<