一、概述
格式:对象::成员方法
这个格式也很好理解,你要想:在之前我们调用成员方法的时候,都是使用对象去调用的,只不过以前是用 .
进行调用的,现在就是使用 ::
进行调用。
在引用成员方法的时候有三种情况需要我们知道
① 其他类:其他类对象::方法名
② 本类:this::方法名
③ 父类:super::方法名
二、练习一
集合中有一些名字,按照要求过滤数据。
数据:“张无忌”,“周芷若”,“赵敏”,“张强”,“张三丰”
要求:只要以张开头,而且名字是3个字的
//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//3.过滤数据(只要以张开头,而且名字是3个字的)
list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(s-> System.out.println(s));
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length() == 3;
}
}).forEach(s-> System.out.println(s));
接下来改为方法引用,要思考:有没有这样的方法,它的形参是字符串,返回值是 boolean
,而且方法里面做的事情跟我现在写的代码是一样的呢?
很显然,Java并没有提供这样的方法,这个时候就可以自己写一个。
新建一个类 StringOperation.java
public class StringOperation {
public boolean stringJudge(String s){
return s.startsWith("张") && s.length() == 3;
}
}
① 其他类:其他类对象::方法名
StringOperation so = new StringOperation();
list.stream().filter(so::stringJudge)
.forEach(s-> System.out.println(s));
② 本类:this::方法名
如果直接在 main方法
中直接用 this
调用下面的方法,会直接报错,因为静态方法中没有 this
!!!
因此如果你想要引用本类的非静态方法,那么引用处必须在非静态的方法中。
但静态方法中没有 this
怎么办呢?这个时候你只能创建本类的对象。
//静态方法中是没有this的
list.stream().filter(new FunctionDemo3()::stringJudge)
.forEach(s-> System.out.println(s));
this::方法名
、super::方法名
会放在第二个练习中讲解,因为这两种方式引用处不能是静态方法,因为在静态方法里面是没有 this
也是没有 super
的。
二、练习二
GUI界面中点击事件的方法引用写法
基础代码
App.java
public class App {
public static void main(String[] args) {
new LoginJFrame();
}
}
LoginJFrame.java
public class LoginJFrame extends JFrame {
JButton go = new JButton("Go");
public LoginJFrame() {
//设置图标
setIconImage(Toolkit.getDefaultToolkit().getImage("myfunction\\image\\logo.jpg"));
//设置界面
initJframe();
//添加组件
initView();
//界面显示出来
this.setVisible(true);
}
//添加组件
public void initView() {
JLabel image = new JLabel(new ImageIcon("myfunction\\image\\kit.jpg"));
image.setBounds(100,50,174,174);
this.getContentPane().add(image);
go.setFont(new Font(null,1,20));
go.setBounds(120,274,150,50);
go.setBackground(Color.WHITE);
this.getContentPane().add(go);
}
//设置界面
public void initJframe() {
//设置标题
this.setTitle("随机点名器");
//设置大小
this.setSize(400, 500);
//设置关闭模式
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口无法进行调节
this.setResizable(false);
//界面居中
this.setLocationRelativeTo(null);
//取消内部默认居中放置
this.setLayout(null);
//设置背景颜色
this.getContentPane().setBackground(Color.white);
this.setAlwaysOnTop(true);//置顶
}
}
需求:点击go之后,在控制台有数据打印
根据之前所学,我们应该给 GO
这个 JButton
添加一个点击事件。
在之前做法,是将本类 implements ActionListener
,go.addActionListener(this);
表示当我们点击 Go按钮
后,就会执行本类里面所对应的 actionPerformed
方法。
public class LoginJFrame extends JFrame implements ActionListener {
JButton go = new JButton("Go");
public LoginJFrame() {
.....
}
//添加组件
public void initView() {
....
go.addActionListener(this);
}
//设置界面
public void initJframe() {
.....
}
@Override
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == go) {
System.out.println("Go按钮被点击了");
}
}
}
那现在我们要用方法引用去做,此时就非常的简单了。
1)本类成员方法引用
此时我们就不需要实现 ActionListener接口
了。
go.addActionListener()
的形参其实是一个接口
跟进 ActionListener
看看,虽然在 ActionListener
上面没有加 @FunctionInterface
,但是它本身是一个接口,里面也只有一个抽象方法,因此它也是一个函数式接口。
既然它是函数式接口,那么就可以在 go.addActionListener()
中去写方法引用了。
ActionListener接口
有一个 actionPerformed()
,因此我们需要去找一个方法,它的形参是 ActionEvent
,返回值是 void
,方法里面干的事情就是我们这个方法里面做的判断。
Java没有给我们提供,我们可以自己写,假设我们写了一个 method()
,此时就可以使用方法引用了。
表示当我们点击了 go按钮
时,就会执行 this(本类)
里面的 method()
。
public class LoginJFrame extends JFrame {
//添加组件
public void initView() {
....
go.addActionListener(this::method);
}
public void method(ActionEvent e) {
Object obj = e.getSource();
if (obj == go) {
System.out.println("Go按钮被点击了");
}
}
}
这样书写可以让我们的代码阅读性得到提高。
例如这个界面中有很多独立的按钮,这样每个按钮我都可以写一个独立的方法:第一个按钮被点击了,我就执行 method1()
;第二个按钮被点击了,我就执行 method2()
里面的代码。
这样来讲,代码更加的独立,以后代码要修改了,有BUG了,其他点击的逻辑就不需要看了,直接看对应的方法就行了。
并且在方法里我们也不需要判断了,因为我们知道,只有当 go
被点击的时候,才会执行 method1()
。
public void method1(ActionEvent e) {
System.out.println("Go1按钮被点击了");
}
public void method2(ActionEvent e) {
System.out.println("Go2按钮被点击了");
}
public void method3(ActionEvent e) {
System.out.println("Go3按钮被点击了");
}
但是如果 method1()
不在本类,而是在父类里面,该怎么办呢?
2)父类成员方法引用
例如我们新写一个 MyJFrame类
public class MyJFrame extends JFrame {
public void method1(ActionEvent e) {
System.out.println("go按钮被点击了");
}
}
然后在 LoginJFrame
中继承 MyJFrame
,并且使用 super::方法名
来引用父类的成员方法。
下面代码就表示我们引用的是父类中的 method1()
public class LoginJFrame extends MyJFrame {
//添加组件
public void initView() {
go.addActionListener(super::method1);
}
}