Java - 访问内部类中的变量或为最终变量赋值

时间:2017-07-04 15:48:53

标签: java inner-classes final

我需要创建几个按钮并上传文件。所以我想创建一个设置这些按钮的功能。但是,我在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,因为我想将file分配给它。

我想知道这个问题是否有任何解决方法。

任何帮助将不胜感激。 :)

感谢@M。普罗霍罗夫和@Chang Liu。 根据{{​​3}}

  

使用但未在内部类中声明的任何局部变量,形式参数或异常参数必须声明为final或者是有效的final,否则会在尝试使用时发生编译时错误。

因此,当我尝试在FileSlectionListener内发送参数file1时,会出现编译错误。但是,Solution中的成员file不是局部变量,因此如果从我的方法中删除File,则不会出现错误。所以@talex的anwser在这种情况下是正确的。

但是,由于我的问题是要找到一种方法将selectedFile传递给内部类并使用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"); } } } 分配变量,我无法找到适合它的方法。我的解决方法是基于@Chang Liu的回答。

我修改后的代码如下:

SimpleTest.obj : error LNK2019: unresolved external symbol "public:
__cdecl SimpleClass::SimpleClass(void)" (??0SimpleClass@@QEAA@XZ) referenced in function "private: void __cdecl SimpleTest::testSimpleClass(void)" (?testSimpleClass@SimpleTest@@AEAAXXZ)

不过,如果你有更好的答案,欢迎给我任何建议。 :)

4 个答案:

答案 0 :(得分:2)

您有两个名为file的变量。一个是类变量,另一个是方法参数。

只需从您的方法中删除参数file,一切正常。

答案 1 :(得分:0)

您可以为文件创建一个可变的包装类:

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()来获取最后选择的文件。

答案 2 :(得分:0)

只需将您的动作侦听器提取为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);
    }
}

答案 3 :(得分:0)

M. Prokhorov's comment所述,如果您转到JLS 8.1.3. Inner Classes and Enclosing Instances,您会看到声明:

  

使用但未在内部类中声明的任何局部变量,形式参数或异常参数必须声明为final或effectively final,否则在尝试使用时会发生编译时错误。

     

关于变量使用的类似规则适用于lambda表达式的主体。

因此,作为变量的方法File file的参数setNewButton在您的内部类new FileSelectionListener的方法{{1}中不是 effectively final },即你为这个变量分配了一个新值,这使得 实际上是最终的

通过为setSelection定义setter而不是传递参数来解决此编译时错误的一些解决方法(但我不确定这是否是最佳做法):

file