繁体   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