The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
Anonymous classes enable you to make your code more concise.匿名类使您的代码更加简洁。They enable you to declare and instantiate a class at the same time.它们使您能够同时声明和实例化一个类。They are like local classes except that they do not have a name.它们与本地类类似,只是它们没有名称。Use them if you need to use a local class only once.如果只需要使用一次本地类,请使用它们。
This section covers the following topics:本节涵盖以下主题:
While local classes are class declarations, anonymous classes are expressions, which means that you define the class in another expression.本地类是类声明,而匿名类是表达式,这意味着您可以在另一个表达式中定义该类。The following example, 以下示例HelloWorldAnonymousClasses
, uses anonymous classes in the initialization statements of the local variables frenchGreeting
and spanishGreeting
, but uses a local class for the initialization of the variable englishGreeting
: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(); } }
As mentioned previously, an anonymous class is an expression.如前所述,匿名类是一个表达式。The syntax of an anonymous class expression is like the invocation of a constructor, except that there is a class definition contained in a block of code.匿名类表达式的语法类似于构造函数的调用,只是代码块中包含一个类定义。
Consider the instantiation of the 考虑frenchGreeting
object: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); } };
The anonymous class expression consists of the following:匿名类表达式由以下内容组成:
The new
operatornew
运算符
The name of an interface to implement or a class to extend.要实现的接口或要扩展的类的名称。In this example, the anonymous class is implementing the interface 在本例中,匿名类正在实现接口HelloWorld
.HelloWorld
。
Parentheses that contain the arguments to a constructor, just like a normal class instance creation expression.包含构造函数参数的括号,就像普通的类实例创建表达式一样。Note: When you implement an interface, there is no constructor, so you use an empty pair of parentheses, as in this example.注意:当您实现一个接口时,没有构造函数,所以您使用一对空括号,如本例所示。
A body, which is a class declaration body.一个主体,它是一个类声明主体。More specifically, in the body, method declarations are allowed but statements are not.更具体地说,在主体中,允许方法声明,但不允许语句。
Because an anonymous class definition is an expression, it must be part of a statement.因为匿名类定义是一个表达式,所以它必须是语句的一部分。In this example, the anonymous class expression is part of the statement that instantiates the 在本例中,匿名类表达式是实例化frenchGreeting
object.frenchGreeting
对象的语句的一部分。(This explains why there is a semicolon after the closing brace.)(这解释了为什么右大括号后面有分号。)
Like local classes, anonymous classes can capture variables; they have the same access to local variables of the enclosing scope:与本地类一样,匿名类可以捕获变量;它们对封闭范围的局部变量具有相同的访问权限:
An anonymous class has access to the members of its enclosing class.匿名类可以访问其封闭类的成员。
An anonymous class cannot access local variables in its enclosing scope that are not declared as 匿名类无法访问其封闭范围中未声明为final
or effectively final.final
或有效最终的局部变量。
Like a nested class, a declaration of a type (such as a variable) in an anonymous class shadows any other declarations in the enclosing scope that have the same name.与嵌套类一样,匿名类中的类型声明(如变量)会隐藏封闭范围中具有相同名称的任何其他声明。See Shadowing for more information.有关详细信息,请参阅阴影。
Anonymous classes also have the same restrictions as local classes with respect to their members:匿名类对其成员也有与本地类相同的限制:
You cannot declare static initializers or member interfaces in an anonymous class.不能在匿名类中声明静态初始值设定项或成员接口。
An anonymous class can have static members provided that they are constant variables.匿名类可以有静态成员,只要它们是常量变量。
Note that you can declare the following in anonymous classes:请注意,您可以在匿名类中声明以下内容:
Fields字段
Extra methods (even if they do not implement any methods of the supertype)额外方法(即使它们不实现任何超类型的方法)
Instance initializers实例初始值设定项
Local classes本地班
However, you cannot declare constructors in an anonymous class.但是,不能在匿名类中声明构造函数。
Anonymous classes are often used in graphical user interface (GUI) applications.匿名类通常用于图形用户界面(GUI)应用程序中。
Consider the JavaFX example 考虑JavaFX示例HelloWorld.java
(from the section Hello World, JavaFX Style from Getting Started with JavaFX).HelloWorld.java
(来自Getting Started with JavaFX的Hello World, JavaFX Style部分)。This sample creates a frame that contains a Say 'Hello World' button.此示例创建一个包含“Hello World”按钮的框架。The anonymous class expression is highlighted:将突出显示匿名类表达式:
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(); } }
In this example, the method invocation 在本例中,方法调用btn.setOnAction
specifies what happens when you select the Say 'Hello World' button.btn.setOnAction
指定当您选择Say'Hello World'按钮时会发生什么。This method requires an object of type 此方法需要EventHandler<ActionEvent>
.EventHandler<ActionEvent>
类型的对象。The EventHandler<ActionEvent>
interface contains only one method, handle.EventHandler<ActionEvent>
接口只包含一个方法handle
。Instead of implementing this method with a new class, the example uses an anonymous class expression.该示例使用匿名类表达式,而不是用新类实现此方法。Notice that this expression is the argument passed to the 请注意,此表达式是传递给btn.setOnAction
method.btn.setOnAction
方法的参数。
Because the 因为EventHandler<ActionEvent>
interface contains only one method, you can use a lambda expression instead of an anonymous class expression.EventHandler<ActionEvent>
接口仅包含一个方法,可以使用lambda表达式而不是匿名类表达式。See the section Lambda Expressions for more information.有关详细信息,请参阅Lambda表达式一节。
Anonymous classes are ideal for implementing an interface that contains two or more methods.匿名类非常适合实现包含两个或多个方法的接口。The following JavaFX example is from the section Customization of UI Controls.下面的JavaFX示例来自UI控件的自定义部分。The highlighted code creates a text field that only accepts numeric values.突出显示的代码创建一个只接受数值的文本字段。It redefines the default implementation of the 它通过重写从TextField
class with an anonymous class by overriding the replaceText
and replaceSelection
methods inherited from the TextInputControl
class.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); } }