Чтобы ответить на ваш вопрос, вам необходимо понять основы того, как 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
делает то, что Требуется, чтобы разработчик объявил переменную внешнего класса как окончательную .
Теперь, когда это сделано, JVM незаметно помещает скрытую переменную с именем val $ edit во 2-й скомпилированный файл класса, вот вывод, полученный из javap
Ouput для 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 назначено то же значение, которое было назначено для редактирования, поскольку теперь компилятор знает, что это значение нельзя изменить, поскольку оно было объявлено как final, и, следовательно, оно работает на этот раз.
А что если я поменяю 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);
}
По-моему, это интерпретация того, как работает эта ситуация.
Только что я нашел в интернете это замечательное объяснение относительно Тайны доступности в местных внутренних классах , может быть, это поможет вам лучше понять ситуацию: -)