java
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class DemoAA extends JFrame{
PanelAA panel;
DemoAA(){
super("练习监听");
setBounds(600, 200, 600, 600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new PanelAA();
add(panel);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(() ->{
new DemoAA().setVisible(true);
});
}
private class PanelAA extends JPanel{
JLabel l1,l2;
int x=0,y=0;
PanelAA(){
setLayout(new GridLayout(2, 1,0,10));
l1 = new JLabel("左上角文字", SwingConstants.LEFT); // 水平左对齐
l1.setVerticalAlignment(SwingConstants.TOP); // 垂直顶部对齐
l1.setFont(new Font("黑体", Font.BOLD, 20));
add(l1);
//鼠标监听
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
x =e.getX();
y=e.getY();
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
});
}
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setFont(new Font("黑体", Font.BOLD, 24));
g2.setColor(Color.RED);
g2.drawString("坐标 X:"+x+" Y:"+y, 10, 60);
}
}
}
为什么匿名内部类能访问外部变量
背后的原理(简单版)
Java 为了让匿名内部类能访问外部变量,实际上在背后偷偷做了这些事:
- 自动传递 :Java 编译器会把外部类的
this
引用(指向PanelAA
实例)传递给匿名内部类 - 隐形桥梁 :匿名内部类通过这个
this
引用,就能找到外部的x
和y
如果是局部变量呢?
有趣的是,如果 x
和 y
是方法内的局部变量(不是类的成员变量),规则就不同了:
java
void someMethod() {
int localX = 0; // 局部变量
addMouseMotionListener(new MouseMotionListener() {
public void mouseMoved(MouseEvent e) {
localX = e.getX(); // 这会报错!不能修改局部变量
}
});
}
这时候 Java 会说:
🚨 "嘿!局部变量
localX
必须声明为final
或等效于final
才能被匿名内部类访问!"
为什么有这个区别?
- 成员变量:属于对象,生命周期和对象一样长,安全可访问
- 局部变量 :方法执行完就可能消失 ,匿名内部类可能活得比它久,所以 Java 要限制