一.引用成员方法的格式:

-
注:这里引用的成员方法一定是非静态的,因为引用静态方法有专门的格式即类名::静态方法名
-
静态方法中是没有this的,所以对于本类中使用this::方法名实现方法引用,必须在非静态方法中
-
静态方法要想使用方法引用来调用本类方法的话,就必须先创建本类的对象,再用该对象去引用方法(这个与 静态内容不能和非静态内容互相调用 无关)
-
非静态方法要想使用方法引用来调用本类方法的话,可以使用this::方法名实现方法引用,也可以先创建本类的对象,再用该对象去引用方法
二.练习一:包含引用其他类的成员方法和引用本类的成员方法
题目:
需求:集合中有一些数据,按照要求过滤数据
数据:"张无忌","周芷若","赵敏","张强","张三丰"(数据为名字,名字要是字符串型)
要求:只要以张开头,而且名字是3个字的数据
解法一:
import java.util.ArrayList;
import java.util.Collections;
public class Main3 {
public static void main(String[] args) {
//1.创建集合
ArrayList<String> list=new ArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//3.过滤数据
list.stream()
.filter(s->s.startsWith("张")) //表示以张开头的数据留下,其他过滤掉
.filter(s->s.length()==3) //表示数据长度为3的留下,其他过滤掉
.forEach(s -> System.out.println(s));
}
}
解法二:
package com.itheima.a01myfunction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;
public class FunctionDemo3 {
public static void main(String[] args) {
//1.创建集合
ArrayList<String> list=new ArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//3.过滤数据
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) { //s代表流里的每一个数据即集合list中的每一个数据
if(s.charAt(0)=='张'&&s.length()==3) return true; //返回true,表示以张开头且数据长度为3的数据留下,其他过滤掉
return false;
}
}).forEach(s-> System.out.println(s));
}
}
解法三:
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;
public class Main3 {
public static void main(String[] args) {
//1.创建集合
ArrayList<String> list=new ArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//3.过滤数据
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length()==3;
}
}).forEach(s -> System.out.println(s));
}
}
解法四:把解法三使用方法引用改写->引用其他类的成员方法
未改写前:
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;
public class Main3 {
public static void main(String[] args) {
//1.创建集合
ArrayList<String> list=new ArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//3.过滤数据
/*
* 使用方法引用的前提:
* 1.引用处必须是函数式接口:此时Predicate接口就是函数式接口
* 2.要引用的方法必须存在(可以是Java写好的,也可以是人为写好的,也可以是一些第三方的工具类),
* 如果不存在,就需要手动写一个
* ->此时Predicate接口中的方法test的形参是字符串型,返回值是布尔类型,而且方法的作用是只要以张开头,而且名字是3个字的数据
* 显然Java没有提供这样的方法(String类里的equals方法不行,因为该equals方法的形参是Object型),人为也没有写过
* ->所以可以自己写一个符合要求的方法
*
* */
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length()==3;
}
}).forEach(s -> System.out.println(s));
}
}
使用方法引用后:
import com.itheima.a01myfunction.StringOperation;
import java.util.ArrayList;
import java.util.Collections;
public class Main3 {
public static void main(String[] args) {
//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
//3.过滤数据
/*
* 使用方法引用的前提:
* 1.引用处必须是函数式接口:此时Predicate接口就是函数式接口
* 2.要引用的方法必须存在(可以是Java写好的,也可以是人为写好的,也可以是一些第三方的工具类),
* 如果不存在,就需要手动写一个
* ->此时Predicate接口中的方法test的形参是字符串型,返回值是布尔类型,而且方法的作用是只要以张开头,而且名字是3个字的数据
* 显然Java没有提供这样的方法(String类里的equals方法不行,因为该equals方法的形参是Object型),人为也没有写过
* ->所以可以自己写一个符合要求的方法
*
* */
//方法一:
list.stream()
.filter(new StringOperation()::stringJudge)
.forEach(s -> System.out.println(s));
/*方法二:
StringOperation so=new StringOperation();
list.stream().filter(so::stringJudge).forEach(s -> System.out.println(s));*/
}
}
package com.itheima.a01myfunction;
public class StringOperation {
/* 在StringOperation类里写一个方法,
该方法要被引用在Predicate接口创建的匿名内部类的test方法处
->要写的方法返回值类型需要和test方法一致:该方法需要返回布尔类型
->要写的方法的命名无需和test方法一致,见名知意即可
->要写的方法的形参需要和test方法一致,形参的命名无需和test方法的形参名一样,见名知意即可
->要写的方法的作用需要和test方法一致,test方法的作用是只要以张开头,而且名字是3个字的数据,
所以要写的方法的作用也是如此
*/
public boolean stringJudge(String str){
return str.startsWith("张") && str.length()==3;
}
/*
* 要被引用的stringJudge方法是一个普通的成员方法,非静态,普通的成员方法需要用对象来调用,
* 而且要被引用的stringJudge方法和引用处test方法所属类不是同一个类,
* 所以在函数式接口Predicate处需要创建一个对象再引用stringJudge方法
*
* */
}
解法五:把解法三使用方法引用改写->引用本类的成员方法
-
静态方法中是没有this的,所以对于本类中使用this::方法名实现方法引用,必须在非静态方法中
-
静态方法要想使用方法引用来调用本类方法的话,就必须先创建本类的对象,再用该对象去引用方法(这个与 静态内容不能和非静态内容互相调用 无关)
-
非静态方法要想使用方法引用来调用本类方法的话,可以使用this::方法名实现方法引用,也可以先创建本类的对象,再用该对象去引用方法
import java.util.ArrayList;
import java.util.Collections;
public class Main4 {
public static void main(String[] args) {
//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
//3.过滤数据
/*
* 使用方法引用的前提:
* 1.引用处必须是函数式接口:此时Predicate接口就是函数式接口
* 2.要引用的方法必须存在(可以是Java写好的,也可以是人为写好的,也可以是一些第三方的工具类),
* 如果不存在,就需要手动写一个
* ->此时Predicate接口中的方法test的形参是字符串型,返回值是布尔类型,而且方法的作用是只要以张开头,而且名字是3个字的数据
* 显然Java没有提供这样的方法(String类里的equals方法不行,因为该equals方法的形参是Object型),人为也没有写过
* ->所以可以自己写一个符合要求的方法
*
* */
//静态方法中是没有this的,所以在静态方法main中list.stream().filter(this::stringJudge);是错的
//此时静态方法要想使用方法引用来调用本类方法的话,就必须创建本类的对象,用该对象再去引用方法
list.stream().filter(new Main4()::stringJudge).forEach(s -> System.out.println(s));
}
/* 在本类里写一个方法,
该方法要被引用在Predicate接口创建的匿名内部类的test方法处
->要写的方法返回值类型需要和test方法一致:该方法需要返回布尔类型
->要写的方法的命名无需和test方法一致,见名知意即可
->要写的方法的形参需要和test方法一致,形参的命名无需和test方法的形参名一样,见名知意即可
->要写的方法的作用需要和test方法一致,test方法的作用是只要以张开头,而且名字是3个字的数据,
所以要写的方法的作用也是如此
*/
public boolean stringJudge(String str){
return str.startsWith("张") && str.length()==3;
}
/*
* 要被引用的stringJudge方法是一个普通的非静态成员方法,普通的成员方法需要用对象来调用,
* 而且要被引用的stringJudge方法和引用处里的test方法是同一个类,又因为引用处在静态方法main里,
* 所以只需要在引用处先创建本类对象再引用方法stringJudge即可
*
* */
}
三.引用本类或父类的成员方法:

-
静态方法中是没有this和super的,所以引用本类的成员方法或引用父类的成员方法时,引用处不能是静态方法
四.练习二:包含引用本类的成员方法和引用父类的成员方法
题目:
需求:GUI界面中点击事件的方法引用写法
前言:



解答:
未使用方法引用前:
测试类:
package com.itheima.a02game;
public class App {
public static void main(String[] args) {
new LoginJFrame();
}
}
LoginJFrame类:
package com.itheima.a02game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginJFrame extends JFrame implements ActionListener {
/* go对象起初只被定义在initView方法中,但需求中在actionPerformed方法中也需要用到go对象,
而且在运行时需要initView方法比actionPerformed方法先运行,
意味着如果actionPerformed方法此时要想用到go对象,就必须从initView方法中获取,此时只能通过形参传递go对象,
但actionPerformed方法是Java已经写好的,而且是被重写的,Java写actionPerformed方法时形参中没有关于go对象的,
所以把go对象只定义在initView方法中是无法传递到actionPerformed方法中的,
此时只能把创建go对象的语句设置为全局变量供全局使用*/
JButton go=new JButton("imagine\\Go.jpg");
public LoginJFrame(){
//设置图标
setIconImage(Toolkit.getDefaultToolkit().getImage("imagine\\logo.jpg"));
//设置界面
initJframe();
//添加组件
initView();
//界面显示出来
this.setVisible(true);
}
//设置界面
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);
}
//添加组件
public void initView(){
JLabel image=new JLabel(new ImageIcon("imagine\\点名.jpg"));
image.setBounds(100,50,174,174);
this.getContentPane().add(image);
//go对象属于全局变量
go.setFont(new Font(null,1,20));
go.setBounds(120,274,150,50);
go.setBackground(Color.WHITE);
//需求:点击go对象后在控制台要有数据打印->给go对象添加点击事件即可->只需要实现ActionListener接口即可
go.addActionListener(this);
/* addActionListener方法在AbstractButton类里而且addActionListener方法非私有即能够继承,
JButton类继承了AbstractButton类,所以JButton类的对象可以调用addActionListener方法,
->go对象属于JButton类,所以go对象可以调用addActionListener方法,
调用addActionListener方法可以添加点击事件,调用addActionListener方法后
需要传入参数this表示点击go对象后就会执行this即本类里所对应的方法即被重写的actionPerformed方法,
因为addActionListener方法的形参是接口ActionListener,该接口有一个抽象方法actionPerformed,
所以调用addActionListener方法就需要重写ActionListener接口里的actionPerformed方法,
在addActionListener方法的形参中传入this,就表示执行ActionListener接口中重写的actionPerformed方法
(传this给addActionListener方法的原因:调用addActionListener方法意味着要操作addActionListener方法的形参,
addActionListener方法的形参是接口ActionListener,接口ActionListener里有一个抽象方法actionPerformed,
此时就需要在本类中重写抽象方法actionPerformed,方法actionPerformed最终就在本类中,
而且要用到actionPerformed方法,由于actionPerformed方法在本类中,所以传this即可调用)
*/
this.getContentPane().add(go);
}
@Override
public void actionPerformed(ActionEvent e) {
//1.获取被点击的按钮对象
Object obj = e.getSource();
//2.判断
if(obj==go){ //意味着形参e如果是go对象即点击了go就会执行if里的打印语句
System.out.println("go按钮被点击了");
}
}
}
使用方法引用改写后:引用本类的成员方法
其实很简单,LoginJFrame类所实现的ActionListener接口可以不实现了,原因如下:
initView方法中go对象调用了addActionListener方法,addActionListener方法的形参是接口ActionListener:

虽然ActionListener接口没有标记函数式接口,但接口ActionListener本身是一个接口,里面也只有一个抽象方法,所以ActionListener接口也是函数式接口,因此可以在addActionListener方法的参数里使用方法引用:

ActionListener接口里有一个抽象方法actionPerformed,在LoginJFrame类里重写了actionPerformed方法:

在addActionListener方法的形参里可以使用方法引用,而且该形参此时用到了actionPerformed方法,为了使用方法引用,就要找一个方法,该方法的形参类型是ActionEvent,该方法的返回值是void,方法的作用就是获取被点击的按钮对象后进行判断,此时发现Java没有提供,之前也没有写过,所以可以自己写:将要写的方法命名为method,返回值为void,形参类型为ActionEvent,作用和actionPerformed方法一致

此时在initView方法中,go对象调用了addActionListener方法处就可以使用method方法实现方法引用,method方法属于本类方法,使用本类方法的方法引用格式为this::方法名:

此时表示点击go按钮后就会执行this本类里的method方法
->提高了代码阅读性,也提高了效率,比如此时需要多个按钮,就可以针对每一个按钮各自写一个方法
->也提高了维护性,比如按钮代码出bug了,其他有关点击的方法的逻辑就不需要看了,直接看对应的方法即可
->对于method方法,还可以继续优化,此时规定了点击go后输出打印,因此也就不需要判断了,当go调用addActionListener方法,就直接调用method方法进行打印,因此可以优化掉method方法里的if语句:

测试类:
package com.itheima.a02game;
public class App {
public static void main(String[] args) {
new LoginJFrame();
}
}
LoginJFrame类:
package com.itheima.a02game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class LoginJFrame extends JFrame {
/* go对象起初只被定义在initView方法中,但需求中在actionPerformed方法中也需要用到go对象,
而且在运行时需要initView方法比actionPerformed方法先运行,
意味着如果actionPerformed方法此时要想用到go对象,就必须从initView方法中获取,此时只能通过形参传递go对象,
但actionPerformed方法是Java已经写好的,而且是被重写的,Java写actionPerformed方法时形参中没有关于go对象的,
所以把go对象只定义在initView方法中是无法传递到actionPerformed方法中的,
此时只能把创建go对象的语句设置为全局变量供全局使用*/
JButton go = new JButton("imagine\\Go.jpg");
public LoginJFrame() {
//设置图标
setIconImage(Toolkit.getDefaultToolkit().getImage("imagine\\logo.jpg"));
//设置界面
initJframe();
//添加组件
initView();
//界面显示出来
this.setVisible(true);
}
//设置界面
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);
}
//添加组件
public void initView() {
JLabel image = new JLabel(new ImageIcon("imagine\\点名.jpg"));
image.setBounds(100, 50, 174, 174);
this.getContentPane().add(image);
//go对象属于全局变量
go.setFont(new Font(null, 1, 20));
go.setBounds(120, 274, 150, 50);
go.setBackground(Color.WHITE);
//需求:点击go对象后在控制台要有数据打印->给go对象添加点击事件即可->只需要实现ActionListener接口即可
go.addActionListener(this::method);
/*addActionListener方法的形参是接口ActionListener,虽然ActionListener接口没有标记函数式接口,
但接口ActionListener本身是一个接口,里面也只有一个抽象方法,所以ActionListener接口也是函数式接口,
所以可以在addActionListener的参数里使用方法引用*/
this.getContentPane().add(go);
}
public void method(ActionEvent e) {
System.out.println("go按钮被点击了");
}
}
使用方法引用改写后:引用父类的成员方法
测试类:
package com.itheima.a02game;
public class App {
public static void main(String[] args) {
new LoginJFrame();
}
}
父类MyJFrame:
package com.itheima.a02game;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class MyJFrame extends JFrame { //父类
//MyJFrame继承JFrame,使得MyJFrame是一个界面
public void method(ActionEvent e) {
System.out.println("go按钮被点击了");
}
}
子类LoginJFrame:
package com.itheima.a02game;
import javax.swing.*;
import java.awt.*;
public class LoginJFrame extends MyJFrame { //MyJFrame的子类
/* MyJFrame继承JFrame,使得MyJFrame是一个界面,
LoginJFrame继承MyJFrame,使得LoginJFrame也是一个界面*/
/* go对象起初只被定义在initView方法中,但需求中在actionPerformed方法中也需要用到go对象,
而且在运行时需要initView方法比actionPerformed方法先运行,
意味着如果actionPerformed方法此时要想用到go对象,就必须从initView方法中获取,此时只能通过形参传递go对象,
但actionPerformed方法是Java已经写好的,而且是被重写的,Java写actionPerformed方法时形参中没有关于go对象的,
所以把go对象只定义在initView方法中是无法传递到actionPerformed方法中的,
此时只能把创建go对象的语句设置为全局变量供全局使用*/
JButton go = new JButton("imagine\\Go.jpg");
public LoginJFrame() {
//设置图标
setIconImage(Toolkit.getDefaultToolkit().getImage("imagine\\logo.jpg"));
//设置界面
initJframe();
//添加组件
initView();
//界面显示出来
this.setVisible(true);
}
//设置界面
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);
}
//添加组件
public void initView() {
JLabel image = new JLabel(new ImageIcon("imagine\\点名.jpg"));
image.setBounds(100, 50, 174, 174);
this.getContentPane().add(image);
//go对象属于全局变量
go.setFont(new Font(null, 1, 20));
go.setBounds(120, 274, 150, 50);
go.setBackground(Color.WHITE);
//需求:点击go对象后在控制台要有数据打印->给go对象添加点击事件即可->只需要实现ActionListener接口即可
go.addActionListener(super::method); //表示引用的是本类的父类的method方法(这里用this::method也可以实现同样的效果,因为继承有一个特性,this::method表示先在本类找method方法,本类找不到自动到父类找method方法,一直向上找,直到找到method方法为止)
/*addActionListener方法的形参是接口ActionListener,虽然ActionListener接口没有标记函数式接口,
但接口ActionListener本身是一个接口,里面也只有一个抽象方法,所以ActionListener接口也是函数式接口,
所以可以在addActionListener的参数里使用方法引用*/
this.getContentPane().add(go);
}
}
initView方法中go对象调用addActionListener方法处用到了方法引用。
2162

被折叠的 条评论
为什么被折叠?



