簡體   English   中英

Java-訪問內部類中的變量或為最終變量分配值

[英]Java - access to variable within inner class or assign a value to final variable

我需要創建幾個按鈕並上傳文件。 所以我想創建一個函數來設置這些按鈕。 但是,我的setNewButton內部出現編譯錯誤。

我的代碼如下所示:

public class Solution extends JFrame {
    private static final String FILE_NAME_1 = "my file1";
    private File file1;
    private void setNewButton(Container contentPane, final String fileName, String format, File file) {
        contentPane.add(Box.createVerticalStrut(5));
        final Label label = new Label("Select " + fileName + " in ." + format +" format");
        contentPane.add(label);
        contentPane.add(Box.createVerticalStrut(10));
        Button selection = new Button("Select " + fileName);
        contentPane.add(selection);
        selection.addActionListener(new FileSelectionListener("Only " + format + " is allowed", format) {
            @Override
            protected void setSelection(File selectedFile) {
                file = selectedFile;  // compilation error here
                label.setText("Selected" + fileName + selectedFile.getAbsolutePath());
            }
        });
    }

    public uploadFiles() {
        Container contentPane = this.getContentPane();
        setNewButton(contentPane, FILE_NAME_1, "xls", file1);
    }
}

錯誤是: Variable file is accessed from within inner class, needs to be declared final

我在stackoverflow中檢查了一些類似的問題。 我知道file必須像這里的labelfileName是最終的。

但是這里的file可能是final因為我想將selectedFile分配給它。

我想知道是否有任何解決此問題的方法。

任何幫助,將不勝感激。 :)

感謝@M。 Prokhorov和@Chang Liu。 根據JLS 8.1.3。 內部類和封閉實例

任何在內部類中使用但未聲明的局部變量,形式參數或異常參數都必須聲明為final或有效地聲明為final,否則在嘗試使用時會發生編譯時錯誤。

因此,當我嘗試在FileSlectionListener內部發送參數file ,將出現編譯錯誤。 但是,解決方案中的成員file1不是局部變量,因此,如果我從方法中刪除file ,則不會有錯誤。 因此,@ talex的答案正確。

但是,由於我的問題是找到一種將File傳遞給內部類並使用selectedFile分配變量的方法,所以我找不到解決方法。 我的解決方法基於@Chang Liu的答案。

我修改后的代碼如下:

public class Solution extends JFrame {
    private static final String FILE_NAME_1 = "my file1";
    private File file1;
    private void setNewButton(Container contentPane, final String fileName, String format) {
        contentPane.add(Box.createVerticalStrut(5));
        final Label label = new Label("Select " + fileName + " in ." + format +" format");
        contentPane.add(label);
        contentPane.add(Box.createVerticalStrut(10));
        Button selection = new Button("Select " + fileName);
        contentPane.add(selection);
        selection.addActionListener(new FileSelectionListener("Only " + format + " is allowed", format) {
            @Override
            protected void setSelection(File selectedFile) {
                setFile(selectedFile, fileName);  // no compilation error here
                label.setText("Selected" + fileName + selectedFile.getAbsolutePath());
            }
        });
    }

    public uploadFiles() {
        Container contentPane = this.getContentPane();
        setNewButton(contentPane, FILE_NAME_1, "xls", file1);
    }

    private void setFile(File file, String fileName) {
        switch (fileName) {
            case FILE_NAME_1:
                sollFile = file;
                break;
            default:
                throw new AssertionError("Unknown File");
        }
    }
}

不過,如果您有更好的答案,歡迎給我任何建議。 :)

您的名稱file有兩個變量。 一個是類變量,另一個是方法參數。

只需從您的方法中刪除參數file ,一切都將正常工作。

您可以為文件創建一個可變的包裝器類:

public class FileWrapper {

    /** The file. */
    private File file;

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }
}

然后,您可以使用該類的最終實例:

final private FileWrapper fileWrapper = new FileWrapper();

// ...     

selection.addActionListener(new FileSelectionListener("Only " + format + " is allowed", format) {
        @Override
        protected void setSelection(File selectedFile) {
            fileWrapper.setFile(selectedFile);  
            label.setText("Selected" + fileName + selectedFile.getAbsolutePath());
        }
    });

並通過在內部類外部調用fileWrapper.getFile()獲得最后選擇的文件。

只需將您的動作偵聽器提取為名稱為Solution的內部類,就可以從內部類中分配Solution.this.file:

public class Solution extends JFrame {
   private class MyListener extends FileSelectionListener{
@Override
            protected void setSelection(File selectedFile) {
                Solution.this.file = selectedFile;  // NO compilation error here
            }
}
    private static final String FILE_NAME_1 = "Selected SOLL:";
    private File file;
    private void setNewButton(Container contentPane, final String fileName, String format, File file) {
        contentPane.add(Box.createVerticalStrut(5));
        final Label label = new Label("Select " + fileName + " in ." + format +" format");
        contentPane.add(label);
        contentPane.add(Box.createVerticalStrut(10));
        Button selection = new Button("Select " + fileName);
        contentPane.add(selection);
        selection.addActionListener(new MyListener() );
    }

    public uploadFiles() {
        Container contentPane = this.getContentPane();
        setNewButton(contentPane, FILE_NAME_1, "xls", file1);
    }
}

M.Prokhorov的評論所述 ,如果您轉到JLS 8.1.3。 內部類和封閉實例 ,您將看到以下內容:

使用但未在內部類中聲明的任何局部變量,形式參數或異常參數必須聲明為final或有效地為final ,否則在嘗試使用時會發生編譯時錯誤。

關於變量使用的類似規則適用於lambda表達式的主體。

因此,在您的內部類new FileSelectionListener的方法setSelection ,方法setNewButton的參數File file作為變量沒有有效地最終 new FileSelectionListener ,即,您為該變量分配了新值,這使其實際上沒有 最終確定

通過為file定義setter而不是傳遞參數來解決此編譯時錯誤的一些解決方法(但我不確定這是否是最佳實踐):

public class Solution extends JFrame {
    private static final String FILE_NAME_1 = "Selected SOLL:";
    private File file;
    private void setNewButton(Container contentPane, final String fileName, String format) {
        contentPane.add(Box.createVerticalStrut(5));
        final Label label = new Label("Select " + fileName + " in ." + format +" format");
        contentPane.add(label);
        contentPane.add(Box.createVerticalStrut(10));
        Button selection = new Button("Select " + fileName);
        contentPane.add(selection);
        selection.addActionListener(new FileSelectionListener("Only " + format + " is allowed", format) {
            @Override
            protected void setSelection(File selectedFile) {
                setFile(selectedFile);  // call file setter here
                label.setText("Selected" + fileName + selectedFile.getAbsolutePath());
            }
        });
    }

    // define a setter for your File member
    private void setFile(File file) {
        this.file = file;
    }

    public void uploadFiles() {
        Container contentPane = this.getContentPane();
        setNewButton(contentPane, FILE_NAME_1, "xls");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM