2

我知道如何使用 final 关键字。假设如果将一个类设为 final 那么它不能被继承,如果一个方法是 final 那么它不能被覆盖,如果一个变量是 final 那么值不能被改变。但是我在这种情况下有点困惑

    final TextField urlTextField = new TextField();

我认为如果 urlTextField 是最终的,那么你不能再做

urlTextField=new textField()。但是在下面的例子中为什么它是最终的

来源

package org.carlfx;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.concurrent.Worker.State;
import javafx.print.*;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.transform.Scale;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

/**
 * Demo to use JavaFX 8 Printer API.
 *
 * @author cdea
 */
public class PrintDemo extends Application {
    @Override
    public void start(Stage primaryStage) {

        final TextField urlTextField = new TextField();
        final Button printButton = new Button("Print");
        final WebView webPage = new WebView();
        final WebEngine webEngine = webPage.getEngine();

        HBox hbox = new HBox();
        hbox.getChildren().addAll(urlTextField, printButton);
        BorderPane borderPane = new BorderPane();
        borderPane.setTop(hbox);
        borderPane.setCenter(webPage);
        Scene scene = new Scene(borderPane, 300, 250);
        primaryStage.setTitle("Print Demo");
        primaryStage.setScene(scene);

        // print button pressed, page loaded
        final BooleanProperty printButtonClickedProperty = new SimpleBooleanProperty(false);
        final BooleanProperty pageLoadedProperty = new SimpleBooleanProperty(false);

        // when the a page is loaded and the button was pressed call the print() method.
        final BooleanProperty printActionProperty = new SimpleBooleanProperty(false);
        printActionProperty.bind(pageLoadedProperty.and(printButtonClickedProperty));

        // WebEngine updates flag when finished loading web page.
        webEngine.getLoadWorker()
                 .stateProperty()
                 .addListener( (ChangeListener) (obsValue, oldState, newState) -> {
                    if (newState == State.SUCCEEDED) {
                        pageLoadedProperty.set(true);
                    }
                 });

        // When user enters a url and hits the enter key.
        urlTextField.setOnAction( aEvent ->  {
            pageLoadedProperty.set(false);
            printButtonClickedProperty.set(false);
            webEngine.load(urlTextField.getText());
        });

        // When the user clicks the print button the webview node is printed
        printButton.setOnAction( aEvent -> {
            printButtonClickedProperty.set(true);
        });

        // Once the print action hears a true go print the WebView node.
        printActionProperty.addListener( (ChangeListener) (obsValue, oldState, newState) -> {
            if (newState) {
                print(webPage);
            }
        });

        primaryStage.show();

    }

    /** Scales the node based on the standard letter, portrait paper to be printed.
     * @param node The scene node to be printed.
     */
    public void print(final Node node) {
        Printer printer = Printer.getDefaultPrinter();
        PageLayout pageLayout = printer.createPageLayout(Paper.NA_LETTER, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT);
        double scaleX = pageLayout.getPrintableWidth() / node.getBoundsInParent().getWidth();
        double scaleY = pageLayout.getPrintableHeight() / node.getBoundsInParent().getHeight();
        node.getTransforms().add(new Scale(scaleX, scaleY));

        PrinterJob job = PrinterJob.createPrinterJob();
        if (job != null) {
            boolean success = job.printPage(node);
            if (success) {
                job.endJob();
            }
        }
    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
4

2 回答 2

7

在 Java 7 之前,您需要声明一个局部变量 final 才能从内部类访问它。

从 Java 8 开始不再需要这个:变量只需要有效地是最终的(即不改变)。该更改与 lambda 语法一致。

因此,从技术上讲,如果您使用的是 Java FX 8,则此处不需要 final 关键字。

于 2013-09-20T06:11:27.773 回答
5

在 Java 7 中,当您在匿名类中并且尝试使用/接近包装类的变量时 - 应该声明该变量,final否则编译器会抱怨。同样的事情也适用于 Lambda 表达式(受 Java 8 支持)。尝试final从声明中删除,你会在第 4 行得到一个编译器错误:

    urlTextField.setOnAction( aEvent ->  {
        pageLoadedProperty.set(false);
        printButtonClickedProperty.set(false);
        webEngine.load(urlTextField.getText()); // <-- compile error 
    });  

文档中:

匿名类无法访问其封闭范围内未声明为 final 或有效 final 的局部变量。

Lambda 表达式和匿名类具有相似的属性(Lambda 表达式可以定义为两件事的组合:代码和范围)。除此之外,与内部类一样,Lambda 表达式只能使用final(或“有效地最终”)在 lambda 之外声明的变量。以下是文档中的示例:

        // The following statement causes the compiler to generate
        // the error "local variables referenced from a lambda expression
        // must be final or effectively final" in statement A:
        //
        // x = 99;

        Block<Integer> myBlock = (y) -> 
        {
            System.out.println("x = " + x); // Statement A
            System.out.println("y = " + y);
            System.out.println("this.x = " + this.x);
            System.out.println("LambdaScopeTest.this.x = " +
                LambdaScopeTest.this.x);
        };
于 2013-09-20T04:51:36.977 回答