Доступ к локальной переменной осуществляется во внутреннем классе (java)

Я получил две ошибки после того, как скомпилировал свой код.

Ошибки:

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

}

Как я могу решить эту ошибку?


person Roubie    schedule 13.04.2011    source источник


Ответы (8)


Вам нужно объявить

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 Внутренние классы и вложенные экземпляры

person edwardsmatt    schedule 13.04.2011
comment
проблема решена. но я не понимаю вашего объяснения. надеюсь, вы могли бы дать больше ... большое спасибо, Эдвард - person Roubie; 13.04.2011
comment
Прикрепил отрывок и ссылку на спецификацию языка Java, надеюсь, это поможет... - person edwardsmatt; 13.04.2011
comment
final необходим, чтобы пользователь не мог изменить переменную, когда она используется внутренним классом/замыканием. Подумайте об этом: если он не помечен как окончательный, внутренние ссылки на класс могут делать все, что может сделать часть кода рядом с объявлением, поэтому вы должны пометить его как окончательный, чтобы избежать проблем параллелизма, и синтаксис обеспечивает это. - person Chris Dennett; 13.04.2011

Если вы объявите переменные как окончательные, это решит ваши ошибки, но, по моему мнению, это не очень хорошее решение проблемы. Аналогичная проблема обсуждалась здесь, вы можете посмотреть здесь для большего понимания.

В решении вашей проблемы вы можете определить методы, используя их, вы можете получить лучшее решение. Для подсказки вы можете прочитать Как получить доступ к неконечной локальной переменной внутри анонимного внутреннего класса

person Mukesh Singh Rathaur    schedule 13.04.2011
comment
В противном случае вы можете объявить переменные ввода и c_age как статическую переменную экземпляра, которая решит вашу проблему. - person Mukesh Singh Rathaur; 13.04.2011

Любая переменная, которую вы используете внутри метода 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);
        }

    }
person Sean Kleinjung    schedule 13.04.2011
comment
Можете ли вы объяснить, почему его нужно объявить окончательным? - person Seth; 18.03.2014

Поскольку добавление 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;
    }
}
person 11684    schedule 28.09.2013

Именованный ввод JTextField был объявлен внутри основного метода. Вероятно, вам следует сделать что-то вроде этого:

  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.
      }

  }

Таким образом, ссылка на ввод внутри внутреннего класса не вызовет проблем.

person Vincent Ramdhanie    schedule 13.04.2011
comment
у меня есть эта ошибка: на нестатическую переменную нельзя ссылаться из статического контекста - person Roubie; 13.04.2011
comment
Основной метод — статический контекст. Вы должны вырваться из этого, создав экземпляр вашего класса, как в моем примере. Различный код из вашего основного метода должен затем войти в конструктор. - person Vincent Ramdhanie; 13.04.2011

Вы должны объявить final две переменные, к которым вы обращаетесь: input и c_age.

Если вы не хотите этого делать, вы можете либо создать новый правильный класс (не специальный) и передать его как параметры в конструкторе, либо (я сделал это при работе с графическими интерфейсами в Java) создать класс слушателя, который берет объекты в своем конструкторе и делает их доступными локально, а затем создает их экземпляры ad-hoc.

person slezica    schedule 13.04.2011

Входная переменная и переменная c_age исчезают после завершения выполнения метода. Вам не будет разрешено использовать эти переменные внутри локальных внутренних классов, если они не являются окончательными.

person Ammu    schedule 13.04.2011

Я только что создал временную переменную в основном классе, например, «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();
    }
}
person Luke Alderton    schedule 04.11.2012