Java™ 教程(匿名類)

匿名類

匿名類能夠使你代碼更簡潔,它們使你可以同時聲明和實例化一個類,它們就像局部類,除了它們沒有名稱,若是你只須要使用局部類一次,請使用它們。java

聲明匿名類

雖然局部類是類聲明,但匿名類是表達式,這意味着你在另外一個表達式中定義該類,如下示例HelloWorldAnonymousClasses在局部變量frenchGreetingspanishGreeting的初始化語句中使用匿名類,但使用局部類初始化變量englishGreetingsegmentfault

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();
    }            
}

匿名類的語法

如前所述,匿名類是表達式,匿名類表達式的語法相似於構造函數的調用,除了代碼塊中包含類定義。oracle

考慮frenchGreeting對象的實例化:app

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);
     }
};

匿名類表達式包含如下內容:ide

  • new運算符。
  • 要實現的接口的名稱或要繼承的類,在此示例中,匿名類正在實現接口HelloWorld
  • 包含構造函數參數的圓括號,就像普通的類實例建立表達式同樣,注意:實現接口時,沒有構造函數,所以你使用一對空括號,如本例所示。
  • 類聲明體,更具體地說,類體中,方法聲明是容許的,但語句不是。

由於匿名類定義是表達式,因此它必須是語句的一部分,在此示例中,匿名類表達式是實例化frenchGreeting對象的語句的一部分(這解釋了爲何在閉合花括號後有一個分號)。函數

訪問封閉範圍的局部變量,以及聲明和訪問匿名類的成員

與局部類同樣,匿名類能夠捕獲變量,它們對封閉範圍的局部變量具備相同的訪問權限:spa

  • 匿名類能夠訪問其封閉類的成員。
  • 匿名類沒法訪問其封閉範圍中未聲明爲final或者實際爲final的局部變量。
  • 與嵌套類同樣,匿名類中的類型(例如變量)的聲明會影響封閉範圍中具備相同名稱的任何其餘聲明,有關更多信息,請參閱遮蔽

匿名類對其成員也具備與局部類相同的限制:code

  • 你不能在匿名類中聲明靜態初始化或成員接口。
  • 匿名類能夠具備靜態成員,前提是它們是常量變量。

請注意,你能夠在匿名類中聲明如下內容:htm

  • 字段
  • 額外的方法(即便他們沒有實現超類型的任何方法)
  • 實例初始化
  • 局部類

可是,你不能在匿名類中聲明構造函數。對象

匿名類的示例

匿名類一般用於圖形用戶界面(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<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("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);
    }
}

上一篇:局部類

下一篇:Lambda表達式

相關文章
相關標籤/搜索