前言
最近在写java事件处理的时候,一开始我基本都是使用传统的java事件处理机制,把实现的接口对象new出来,传到监听器里面去,然后后面用匿名内部类以及lambda表达式的写法都写了一遍(在很多框架的源码里面匿名内部类以及lambda表达式感觉比较常见),然后我发现我对这个匿名内部类以及lambda表达式只是知道写法,却并不知所以然,我也很好奇三种写法中编译器大概做了哪些优化,所以略微去了解了一下做做笔记。
一、匿名内部类
需要创建不会被再次使用的对象,在这种情况下,适合使用匿名内部类。这种类没有名称,是在同一条语句中声明和创建的。既然是匿名类,所以你无法在别的地方实例化和使用这个类。匿名内部类也可用于接口(interface)的实现。前提是必须是类或者接口,且类或者接口中只有一个抽象方法的时候,从匿名内部类到lambda相当于是帮我们越来越简化代码,这样我们简化代码的时候,编译器才能匹配到你的具体实现)
1.特点
匿名对象:没有名字的对象。 new ClassName().run();
非匿名对象:含有名字的对象。 ClassName c=new ClassName(); c.run();
2、语法(举例说明)
举例1:创建一个父类,使用匿名内部类就相当于创建一个父接口的实现子接口。
public abstract class Animal {
public abstract void eat();
}
/**
* 前提
* 必须是类或者接口
* 类或者接口中只有一个抽象方法的时候
*/
public class Demo01 {
public static void main(String[] args) {
//这个匿名内部类整体就等效于:是Animal父类的子类对象
new Animal(){
@Override
public void eat() {
System.out.println("修狗");
}
};
//调用方法1
new Animal(){
@Override
public void eat() {
System.out.println("修狗");
}
}.eat();
//调用方法二
String name="中华田园犬";
//通过匿名内部类访问局部变量,在JDK8版本之前,需要用final关键字,现在可以自动默认了
Animal a=new Animal() {
@Override
public void eat() {
System.out.println(name+"修狗");
}
};
a.eat();
}
}
举例2:创建两个父接口(方法中一个带参数,一个不带参数),并使用匿名内部类、lambda进行函数传参
public interface Inter {
public void method();
}
public interface Inter2 {
int add(int x,int y);
}
public class Demo02 {
public static void main(String[] args) {
//如果想调用function方法,常规方法要先创建一个实现Inter的接口(new出来)传进去
//但是使用匿名内部类可以直接这样
function(new Inter() {
@Override
public void method() {
System.out.println("匿名内部类重写后的方法");
}
});
//使用Lambda表达式,更加简介,直接写逻辑实现,具体的匹配编译器会帮我们实现
function(()->{
System.out.println("Lambda表达式改写后的方法");
});
//带参数的匿名内部类
function2(new Inter2() {
@Override
public int add(int x, int y) {
return x+y;
}
});
//带参数的Lambda表达式
function2((int x,int y)->{
return x+y;
});
}
public static void function(Inter i){
i.method();
}
public static void function2(Inter2 i){
int num=i.add(1,2);
System.out.println("带参数的Lambda表达式:"+num);
}
}
二、lambda表达式
lambda表达式是一个匿名函数,它是推动Java 8发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda表达式可以使代码变的更加简洁紧凑。
1.特点
(形式参数)->{代码块}
Lambda表达式组成三要素:括号,箭头,代码块
Lambda表达式的代码分析
● (): 里面没有内容,可以看成是方法形式参数为空
● ->:用箭头指向后面要做的事情
● {}: 包含一段代码,我们称之为代码块,可以看成是方法体中的内容
2.语法(举例说明)
用匿名内部类和Lambda表达式分别启动一个线程,相对于匿名内部类,我们会发现 Lambda 表达式更简洁。
public class RunableDemo01 {
public static void main(String[] args) {
//匿名内部类的方式启动一个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程启动啦");
}
}).start();
//Lambda表达式的方式启动一个线程
new Thread(()-> System.out.println(Thread.currentThread().getName()+"线程启动啦")).start();
}
}
三、java事件处理模式
处理模式流程如图所示(wps画的略微有些粗糙,总体思想意思差不多)
处理事件四种常见写法(第一种写法贴全部demo代码,剩余三种是在第一种写法的基础上贴变化的部分)
1.写法1
创建了实现了ActionListener接口的监视器listener,并 text.addActionListener(listener)传进去。
public class Demo03{
public static void main(String[] args) {
WindowActionEvent windowActionEvent=new WindowActionEvent();
windowActionEvent.setBounds(100,100,310,260);
windowActionEvent.setTitle("处理ActionEvent事件");
}
}
class WindowActionEvent extends JFrame {
JTextField text ;
ReaderListen listener;
public WindowActionEvent(){
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init(){
setLayout(new FlowLayout());
text=new JTextField(10);
//传统思路
listener=new ReaderListen();
text.addActionListener(listener);
add(text);
}
}
class ReaderListen implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
String str=e.getActionCommand();
System.out.println(str.length());
}
}
2.写法2
不需要创建上面的类ReaderListen ,直接使用匿名内部类传参,
//使用匿名内部类,简化代码
text.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("使用匿名内部类");
}
});
3.写法3
甚至不需要知道类名,直接写实现逻辑,不过注意使用前提是类或者接口中只有一个抽象方法的时候
```bash
//使用Lambda表达式,更加简介
text.addActionListener(d->{
System.out.println("使用Lambda表达式");
});
4.写法4
在实际开发中,如果事件处理的逻辑比较复杂,考虑到维护代码质量以及低耦合的考虑,会将第三种表达式中的逻辑实现封装成一个函数里面。
void init(){
setLayout(new FlowLayout());
text=new JTextField(10);
//传统思路
//使用Lambda表达式,d是参数
text.addActionListener(d->{
onClick(d);
});
add(text);
}
//用自定义函数onClick封装逻辑
public void onClick(ActionEvent event){
System.out.println("lambda但是解耦版");
}