简体   繁体   English

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

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

I need to create several buttons and upload files. 我需要创建几个按钮并上传文件。 So I want to create a function to set these buttons. 所以我想创建一个函数来设置这些按钮。 However, I'm getting a compilation error inside of my setNewButton . 但是,我的setNewButton内部出现编译错误。

My code is shown as below: 我的代码如下所示:

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

The error is: Variable file is accessed from within inner class, needs to be declared final 错误是: Variable file is accessed from within inner class, needs to be declared final

I have checked some similar questions in stackoverflow. 我在stackoverflow中检查了一些类似的问题。 I know file has to be final like label and fileName here. 我知道file必须像这里的labelfileName是最终的。

However file here could be final since I would like to assign selectedFile to it. 但是这里的file可能是final因为我想将selectedFile分配给它。

I would like to know if there is any walkaround for this problem. 我想知道是否有任何解决此问题的方法。

Any help would be appreciated. 任何帮助,将不胜感激。 :) :)

Thanks to @M. 感谢@M。 Prokhorov and @Chang Liu. Prokhorov和@Chang Liu。 According to JLS 8.1.3. 根据JLS 8.1.3。 Inner Classes and Enclosing Instances 内部类和封闭实例

Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final, or a compile-time error occurs where the use is attempted. 任何在内部类中使用但未声明的局部变量,形式参数或异常参数都必须声明为final或有效地声明为final,否则在尝试使用时会发生编译时错误。

So when I tried to send a parameter file inside FileSlectionListener , there will be a compile error. 因此,当我尝试在FileSlectionListener内部发送参数file ,将出现编译错误。 However, the member file1 inside Solution is not local variable, so if I delete the file from my method, there will be no error. 但是,解决方案中的成员file1不是局部变量,因此,如果我从方法中删除file ,则不会有错误。 So @talex 's anwser is right in this case. 因此,@ talex的答案正确。

However since my problem is to find a method to pass a File to inner class and assign the variable with selectedFile , I couldn't find a way for it. 但是,由于我的问题是找到一种将File传递给内部类并使用selectedFile分配变量的方法,所以我找不到解决方法。 My workaround is based on @Chang Liu's answer. 我的解决方法基于@Chang Liu的答案。

My revised code is as below: 我修改后的代码如下:

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

Still, welcome to give me any advise if you have a better answer. 不过,如果您有更好的答案,欢迎给我任何建议。 :) :)

You have two variables with name file . 您的名称file有两个变量。 One is class variable and another is method parameter. 一个是类变量,另一个是方法参数。

Just remove parameter file from your method and all will work fine. 只需从您的方法中删除参数file ,一切都将正常工作。

You can create yourself a mutable wrapper class for the file: 您可以为文件创建一个可变的包装器类:

public class FileWrapper {

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

    public File getFile() {
        return file;
    }

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

Then you can use a final instance of that class: 然后,您可以使用该类的最终实例:

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

And get the last selected file by calling fileWrapper.getFile() outside of your inner class. 并通过在内部类外部调用fileWrapper.getFile()获得最后选择的文件。

Just extract your action listener to be named inner class of Solution and you will be able to assign Solution.this.file from the inner class : 只需将您的动作侦听器提取为名称为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);
    }
}

As stated from M. Prokhorov's comment , if you go to the JLS 8.1.3. M.Prokhorov的评论所述 ,如果您转到JLS 8.1.3。 Inner Classes and Enclosing Instances , you will see it is stated that: 内部类和封闭实例 ,您将看到以下内容:

Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final or be effectively final , or a compile-time error occurs where the use is attempted. 使用但未在内部类中声明的任何局部变量,形式参数或异常参数必须声明为final或有效地为final ,否则在尝试使用时会发生编译时错误。

Similar rules on variable use apply in the body of a lambda expression. 关于变量使用的类似规则适用于lambda表达式的主体。

So the parameter File file of method setNewButton as a variable is not effectively final in your inner class new FileSelectionListener 's method setSelection , ie, you assigned a new value to this variable, which makes it not effectively final . 因此,在您的内部类new FileSelectionListener的方法setSelection ,方法setNewButton的参数File file作为变量没有有效地最终 new FileSelectionListener ,即,您为该变量分配了新值,这使其实际上没有 最终确定

Some workaround to resolve this compile-time error, by defining a setter for file instead of passing an argument (but I am not sure whether this is a best practice): 通过为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