#java #actionlistener #inner-classes #final
#java #actionlistener #внутренние классы #Финал
Вопрос:
Я получил две ошибки после того, как скомпилировал свой код.
Ошибки являются:
1.
local variable input is accessed within inner class;
needs to be declared final
String name = input.getText();
2.
local variable c_age is accessed within inner class;
needs to be declared final
Object child_age = c_age.getSelectedItem();
Это мой код:
import javax.swing.*;
import java.awt.event.*;
public class GUI
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Try GUI");
JLabel l1 = new JLabel("Please Enter Your Child's Name");
JTextField input = new JTextField("",10);
JLabel l2 = new JLabel("Choose Your Child's Age");
String[] age = {"Age","1","2","3","4","5","6"};
JComboBox c_age = new JComboBox(age);
JButton button = new JButton("Search");
JTextArea result = new JTextArea();
JScrollPane extend_area = new JScrollPane(result);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
String name = input.getText();
Object child_age = c_age.getSelectedItem();
}
});
JPanel panel = new JPanel();
panel.add(l1);
panel.add(input);
panel.add(l2);
panel.add(c_age);
panel.add(button);
panel.add(extend_area);
frame.add(panel);
frame.setSize(350,350);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Как я могу устранить эту ошибку?
Ответ №1:
Вам нужно объявить
JTextField input = new JTextField("",10);
и
JComboBox c_age = new JComboBox(age);
вот так:
final JTextField input = new JTextField("",10);
final JComboBox c_age = new JComboBox(age);
Это означает, что input
и c_age
не может измениться:
Любая локальная переменная, используемая, но не объявленная во внутреннем классе, должна быть определенно назначена перед телом внутреннего класса.
Объяснение взято из спецификации языка Java, раздел — 8.1.3 внутренние классы и заключающие их экземпляры
Комментарии:
1. проблема решена. но я не понимаю вашего объяснения. надеюсь, вы могли бы дать больше… большое спасибо, Эдвард
2. Прилагаю выдержку и ссылку на спецификацию языка Java, надеюсь, это поможет…
3. final необходим для того, чтобы пользователь не мог изменить переменную, когда она используется внутренним классом / закрытием. Подумайте об этом: если она не помечена как final, ссылки на внутренние классы могут делать все, что может делать фрагмент кода рядом с объявлением, поэтому вы должны пометить ее как final, чтобы избежать проблем с параллелизмом, и синтаксис обеспечивает это.
Ответ №2:
Если вы объявите переменные как конечные, это исправит ваши ошибки, но, по моему мнению, это не самое лучшее решение проблемы. Аналогичная проблема обсуждалась здесь, вы можете посмотреть здесь для большего понимания.
В решении вашей проблемы вы можете определить методы, используя их, вы можете получить лучшее решение. Для подсказки вы можете прочитать, как получить доступ к не окончательной локальной переменной внутри анонимного внутреннего класса
Комментарии:
1. Другим способом вы можете объявить свои входные переменные и переменные c_age как статическую переменную экземпляра, что решит вашу проблему.
Ответ №3:
Любая переменная, которую вы используете внутри actionPerformed
метода вашего внутреннего класса, должна быть объявлена final. Попробуйте следующее:
import javax.swing.*;
import java.awt.event.*;
public class GUI
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Try GUI");
JLabel l1 = new JLabel("Please Enter Your Child's Name");
final JTextField input = new JTextField("",10);
JLabel l2 = new JLabel("Choose Your Child's Age");
String[] age = {"Age","1","2","3","4","5","6"};
final JComboBox c_age = new JComboBox(age);
JButton button = new JButton("Search");
JTextArea result = new JTextArea();
JScrollPane extend_area = new JScrollPane(result);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
String name = input.getText();
Object child_age = c_age.getSelectedItem();
}
});
JPanel panel = new JPanel();
panel.add(l1);
panel.add(input);
panel.add(l2);
panel.add(c_age);
panel.add(button);
panel.add(extend_area);
frame.add(panel);
frame.setSize(350,350);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Комментарии:
1. Можете ли вы объяснить, почему она должна быть объявлена окончательной?
Ответ №4:
Поскольку добавление final
отнимает много гибкости, я хотел бы предложить следующее: создайте метод доступа, который в любом случае поощряется. Но это в основном полезно при работе с объектами, в то время как в вашем случае все статично. Следовательно, этот ответ может не относиться к вашей конкретной ситуации, но поскольку поиск в Google вашего сообщения об ошибке выдает этот вопрос в качестве наилучшего результата, я думаю, что альтернатива, которая применима в большинстве случаев (использование объектов более распространено, чем выполнение всего из статического метода), также должна присутствовать здесь.
public class MyClass extends MySuperClass {
private MyPropertyClass aProperty;
public MyClass() {
new JButton().setActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// aProperty.aMethod(); -- Bang! That should be final, the compiler says.
getMyProperty().aMethod(); // -- Everything okay, works fine, no compiler complaints.
}
});
}
public getMyProperty() {
return aProperty;
}
}
Ответ №5:
JTextField с именем input был объявлен внутри метода main. Вероятно, вам следует сделать что-то вроде этого:
public class GUI{
//declare all your components here e.g.
JTextField input;
public static void main(String args[]){
new GUI();
}
public GUI(){
//instantiate components here
input = new JTextField();
//and so on.
}
}
Таким образом, ссылка на входные данные внутри внутреннего класса не вызовет проблем.
Комментарии:
1. у меня такая ошибка: на нестатическую переменную нельзя ссылаться из статического контекста
2. Основным методом является статический контекст. Вы должны выйти из него, создав экземпляр вашего класса, как в моем примере. Затем различный код из вашего основного метода должен быть помещен в конструктор.
Ответ №6:
Вы должны объявить final
две переменные, к которым вы обращаетесь: input
и c_age
.
Если вы не хотите этого делать, то вы можете либо создать новый соответствующий класс (не специальный) и передать их в качестве параметров в конструкторе, либо (я делал это при работе с графическим интерфейсом в Java) создать класс-прослушиватель, который принимает объекты в своем конструкторе и делает их доступными локально, а затем создать их экземпляр ad-hoc.
Ответ №7:
Входная переменная и переменная c_age исчезают после завершения выполнения метода. Вам не будет разрешено использовать эти переменные внутри локальных внутренних классов, если это не является окончательным.
Ответ №8:
Я только что создал временную переменную в основном классе, например ‘tempString’, а затем для нее можно установить переменную, которая вызывает проблему. Итак:
tempString = myString
таким образом, я могу вызвать tempString вообще без каких-либо проблем. Посмотрите мой пример ниже:
// Create my temp var here
private String tempUrl;
// my function here
public void updatePage(String url)
{
// Can use 'url' here because it's not within inner class
if(!url.equals(""))
{
// Set 'tempUrl' to 'url' so I can use it without problem
tempUrl = url;
// My inner class that used to cause the problem
backgroundUpdate = new Thread(new Runnable()
{
// From here on I use 'tempUrl' to solve the problem
public void run()
{
// Do something with 'tempUrl' here (where 'url' used to be used)
}
});
backgroundUpdate.start();
}
}