Чтобы ответить на ваш вопрос, вам необходимо понять основы работы JVM. Когда классы компилируются, которые содержат внутренние классы, генерируемый байт-код фактически не реализует внутренние классы как класс внутри класса.
ПОЧЕМУ ОШИБКА: доступ к локальной переменной осуществлялся из внутреннего класса, необходимо объявить ее окончательной
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
public foo()
{
final JMenu edit = new JMenu();
edit.getItem(0).addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
Когда вы скомпилируете эту программу, будут созданы два файла: Foo.class и Foo $ 1.class. Итак, теперь возникает ваша проблема, поскольку класс Second
, т.е. foo$1.class
, не знает, что Variable
edit присутствует внутри класса First
, т.е. foo.class
.
Итак, как решить эту проблему? Что делает JVM
, так это то, что он требует от разработчика объявить переменную внешнего класса как final.
Теперь это сделано, теперь JVM незаметно помещает скрытую переменную с именем val $ edit во второй скомпилированный файл класса, вот результат, полученный от javap
Выход для foo.class
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
public foo();
}
Теперь, поскольку редактирование является локальным для конструктора, поэтому результат такой же, как и выше.
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final javax.swing.JMenu val$edit;
final foo this$0;
foo$1(foo, javax.swing.JMenu);
public void mouseClicked(java.awt.event.MouseEvent);
}
Variable
val $ edit назначается то же значение, которое было назначено для редактирования, поскольку теперь компилятор знает, что значение не может быть изменено, поскольку оно было объявлено окончательным, и, следовательно, на этот раз оно работает.
Что, если я изменю edit Variable
с Local
на Instance
. Теперь объект класса знает все об этой переменной edit, если она изменится. Таким образом, изменяя указанную выше программу аналогично, мы получаем:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
JMenu edit = new JMenu();
public foo()
{
edit.getItem(0).addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
Здесь, в этом случае, мы не предполагаем объявлять и определять его как final
, потому что в этом случае, поскольку Variable
является локальным для всего класса, Variable
отправляется внутреннему классу вместе с Object Reference
, т.е. this
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
javax.swing.JMenu edit;
public foo();
}
Вот как в этом случае отправляется Variable
, то есть этот $ 0:
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final foo this$0;
foo$1(foo);
public void mouseClicked(java.awt.event.MouseEvent);
}
По-моему, это такая интерпретация того, как работает эта ситуация. Только что я нашел в Интернете замечательное объяснение Тайны доступности в Локальные внутренние классы, возможно, это поможет вам лучше понять ситуацию :-)
person
nIcE cOw
schedule
03.11.2012