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
错误是:从内部类中访问变量文件,需要声明为final
I have checked some similar questions in *. I know file
has to be final like label
and fileName
here.
我在*中检查了一些类似的问题。我知道文件必须像label和fileName这样最终。
However file
here could be final
since I would like to assign selectedFile
to it.
但是这里的文件可能是最终的,因为我想将selectedFile分配给它。
I would like to know if there is any walkaround for this problem.
我想知道这个问题是否有任何解决方法。
Any help would be appreciated. :)
任何帮助,将不胜感激。 :)
Thanks to @M. Prokhorov and @Chang Liu. According to JLS 8.1.3. Inner Classes and Enclosing Instances
感谢@M。普罗霍罗夫和@Chang Liu。根据JLS 8.1.3。内部类和封闭实例
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. However, the member file1
inside Solution is not local variable, so if I delete the file
from my method, there will be no error. So @talex 's anwser is right in this case.
因此,当我尝试在FileSlectionListener中发送参数文件时,将出现编译错误。但是,Solution里面的成员file1不是局部变量,所以如果我从我的方法中删除文件,就没有错误。所以@talex的anwser在这种情况下是正确的。
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. My workaround is based on @Chang Liu's answer.
但是,由于我的问题是找到一个方法将File传递给内部类并使用selectedFile分配变量,我无法找到它的方法。我的解决方法基于@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. :)
如果你有更好的答案,欢迎给我任何建议。 :)
4 个解决方案
#1
0
As stated from M. Prokhorov's comment, if you go to the JLS 8.1.3. Inner Classes and Enclosing Instances, you will see it is stated that:
正如M. Prokhorov的评论所述,如果你去JLS 8.1.3。内部类和封闭实例,您将看到它被声明:
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
, i.e., you assigned a new value to this variable, which makes it not effectively final.
因此,方法setNewButton的参数文件文件作为变量在内部类中不是最终的新FileSelectionListener的方法setSelection,即,您为此变量分配了一个新值,这使得它不是最终的。
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):
解决此编译时错误的一些解决方法,通过为文件定义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");
}
}
#2
2
You have two variables with name file
. One is class variable and another is method parameter.
您有两个带有名称文件的变量。一个是类变量,另一个是方法参数。
Just remove parameter file
from your method and all will work fine.
只需从您的方法中删除参数文件,一切正常。
#3
0
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()来获取最后选择的文件。
#4
0
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);
}
}
#1
0
As stated from M. Prokhorov's comment, if you go to the JLS 8.1.3. Inner Classes and Enclosing Instances, you will see it is stated that:
正如M. Prokhorov的评论所述,如果你去JLS 8.1.3。内部类和封闭实例,您将看到它被声明:
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
, i.e., you assigned a new value to this variable, which makes it not effectively final.
因此,方法setNewButton的参数文件文件作为变量在内部类中不是最终的新FileSelectionListener的方法setSelection,即,您为此变量分配了一个新值,这使得它不是最终的。
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):
解决此编译时错误的一些解决方法,通过为文件定义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");
}
}
#2
2
You have two variables with name file
. One is class variable and another is method parameter.
您有两个带有名称文件的变量。一个是类变量,另一个是方法参数。
Just remove parameter file
from your method and all will work fine.
只需从您的方法中删除参数文件,一切正常。
#3
0
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()来获取最后选择的文件。
#4
0
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);
}
}