Mouse adapter volume

I am wondering what the scope of the MouseAdapter is.

class foo extends JPanel()
{
  private JMenu edit = new JMenu();
  public foo()
  {
      this.edit.getItem(0).addMouseListener(new MouseAdapter(){ 
          @Override
          public void mouseClicked(MouseEvent e) {
              if (e.getClickCount() == 1) {
                  edit.getItem(0).setEnabled(true);
              }
          } 
      });
  }
}

      

I thought the MouseAdapter has access to the edit variable because the newly declared MouseAdapter is an inner class of the foo class . However, it cannot find the variable to change . If I explicitly declare an inner class and implement, say, the MouseAdapter interface or whatever, it can detect the variable to edit from within. So my question is what the scope of the new MouseAdpater () has? Also, does anyone know good about this? Many thanks. By the way, the error I got was that the local variable was obtained from the inner class, you need to declare it final

+3


source to share


3 answers


1) edit.getItem(0)

returns fist JMenuItem

if exists, otherwise returnsIllegalArgumentException

2) this.edit.getItem(0)

, not a class returning elements

3) edit.getItem(0).addMouseListener(new MouseAdapter(){

is counterproductive because JMenu

, JMenuItem

correctly implemented MouseEvents

, for a better workaround, you should lookButtonModel



4) no reason to scope of the mouse adapter

5) to listen for events from JMenu

(not JMenuItem

) seeMenuListener

+3


source


To answer your question, you need to understand the basics of how to use the JVM to work. When classes are compiled that contain inner classes, the bytecode that is generated does not actually implement the inner classes as a class within a class.

WHY ERROR: The local variable was accessible from the inner class, it needs to be declared definitively

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

      

When you compile your program, two files will be generated, Foo.class and Foo $ 1.class. So now your problem occurs because the Second

ie class foo$1.class

does not know what is Variable

editpresent inside the First

ie class foo.class

.

So how do you fix this problem? What it does JVM

is . This requires the developer to make the external class variable final .

Now that this is done, the JVM is now quietly placing a hidden variable named val $ edit inside the second compiled class file, here is the result obtained from javap

Output for foo.class

C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
  public foo();
}

      

Now, since the edit is local to the constructor, hence the output is as above.



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

      

The Variable

val $ editor is assigned the same value that was assigned for editing, since the compiler now knows that the value cannot be changed since it was declared final, and hence it works this time.

Now if I changed edit Variable

to Local

to Instance

. Now the class object knows everything about this variable editif it is changed. Therefore, by changing the above program, we get:

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

      

Here, in this case, we do not have to declare and define it as final

, because in this case, since it Variable

is local to the entire class, it is Variable

sent to the Inner class along with Object Reference

i.e.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();
}

      

This is how it is Variable

sent in this case, i.e. this $ 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);
}

      

In my opinion, this is an interpretation of how this situation works. Just now I found this great explanation on the internet regarding Mystery of Accessibility in Local Inner Classes , maybe this will help you understand the situation in pretty much a better way :-)
+3


source


Your anonymous inner class exists, as you would expect, in the scope of its parent. The scope is not a problem.

As the error message suggests, an anonymous inner class can only access its parent "edit" if that member is declared final.

So change

  private JMenu edit = new JMenu();

      

to

  private final JMenu edit = new JMenu();

      

and it should work.

+1


source







All Articles