javaSE_8系列博客——Java语言的特性(三)--类和对象(18)--嵌套类(匿名类)
2017-05-14 22:02
946 查看
匿名类使您能够使您的代码更简洁。它们使您能够同时声明和实例化一个类。他们就像局部类,除了他们没有名字。如果您只需要使用一次局部类,请使用匿名类。
匿名类表达式包含以下内容:
new操作符
要实现的接口的名称或扩展的类。在这个例子中,匿名类正在实现接口HelloWorld
包含构造函数的参数的括号,就像普通类实例创建表达式一样。注意:实现一个接口时,没有构造函数,所以你使用一对空的圆括号,就像这个例子一样。
一个类体,这是一个类声明体。更具体地说,在类体中,方法声明是允许的,但是语句不是。
因为匿名类定义是一个表达式,它必须是语句的一部分。在此示例中,匿名类表达式是实例化frenchGreeting对象的语句的一部分。 (这解释了为什么在关闭括号后面有一个分号。)
一个匿名类可以访问其封闭类的成员
匿名类不能访问其封闭范围内未被声明为final或有效final的局部变量
像嵌套类一样,匿名类中的类型声明(如变量)会影响包含相同名称的封闭范围内的任何其他声明。
匿名类和局部类,在与其成员的访问控制上也有相同的限制:
您无法在匿名类中声明静态初始化程序或成员接口
匿名类可以有静态成员,只要它们是常量变量
请注意,您可以在匿名类中声明以下内容:
字段
扩展方法(即使它们没有实现任何超类型的方法)
实例初始化器
局部类
注意:您不能在匿名类中声明构造函数。
我们来看看JavaFX示例HelloWorld.java(从Hello World部分开始,JavaFX入门的JavaFX样式)。此示例创建一个包含Say’Hello World’按钮的框架。匿名类表达式突出显示:
在这个例子中,方法调用btn.setOnAction指定当您选择Say’Hello World’按钮时会发生什么。此方法需要一个类型为EventHandler 的对象。 EventHandler 接口只包含一个方法,句柄。该示例使用匿名类表达式而不是使用新类实现此方法。请注意,此表达式是传递给btn.setOnAction方法的参数。
因为EventHandler 接口只包含一个方法,所以您可以使用lambda表达式而不是匿名类表达式。
匿名类是实现包含两个或更多方法的接口的理想选择。以下JavaFX示例来自UI控件的自定义部分。突出显示的代码创建一个仅接受数值的文本字段。它通过覆盖从TextInputControl类继承的replaceText和replaceSelection方法,通过匿名类重新定义TextField类的默认实现。
声明一个匿名类
局部类是类声明,但匿名类是表达式,这意味着您在另一个表达式中定义类。以下示例HelloWorldAnonymousClasses在局部变量frenchGreeting和spanishGreeting的初始化语句中使用匿名类,但是使用局部类来初始化变量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’按钮的框架。匿名类表达式突出显示:
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 的对象。 EventHandler 接口只包含一个方法,句柄。该示例使用匿名类表达式而不是使用新类实现此方法。请注意,此表达式是传递给btn.setOnAction方法的参数。
因为EventHandler 接口只包含一个方法,所以您可以使用lambda表达式而不是匿名类表达式。
匿名类是实现包含两个或更多方法的接口的理想选择。以下JavaFX示例来自UI控件的自定义部分。突出显示的代码创建一个仅接受数值的文本字段。它通过覆盖从TextInputControl类继承的replaceText和replaceSelection方法,通过匿名类重新定义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<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); } }
相关文章推荐
- javaSE_8系列博客——Java语言的特性(三)--类和对象(15)--嵌套类
- javaSE_8系列博客——Java语言的特性(三)--类和对象(16)--嵌套类(内部类的示例)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(20)--嵌套类(Lambda 表达式--VS--方法引用)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(19)--嵌套类(Lambda 表达式)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(17)--嵌套类(本地/局部类)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(14)--初始化字段
- javaSE_8系列博客——Java语言的特性(三)--类和对象(21)--何时使用Lambda 表达式?
- javaSE_8系列博客——Java语言的特性(三)--类和对象(8)--对象
- javaSE_8系列博客——Java语言的特性(三)--类和对象(4)--声明成员变量
- javaSE_8系列博客——Java语言的特性(三)--类和对象(1)--概述
- javaSE_8系列博客——Java语言的特性(三)--类和对象(7)--给方法或者构造器传输信息
- javaSE_8系列博客——Java语言的特性(三)--类和对象(10)--对象的使用
- javaSE_8系列博客——Java语言的特性(三)--类和对象(2)--类(宏观概述)
- javaSE_8系列博客——Java语言的特性(三)--类和对象(12)--类成员的访问控制
- javaSE_8系列博客——Java语言的特性(一)--关于面向对象基本概念的理解(1)
- javaSE_8系列博客——Java语言的特性(一)--关于面向对象基本概念的理解(2)--对象
- javaSE_8系列博客——Java语言的特性(三)--类和对象(5)--定义方法
- javaSE_8系列博客——Java语言的特性(三)--类和对象(3)--类的声明
- javaSE_8系列博客——Java语言的特性(三)--类和对象(21)--枚举类型
- javaSE_8系列博客——Java语言的特性(三)--类和对象(13)--理解类的成员