【Java】引用成员方法

一、概述

格式:对象::成员方法

这个格式也很好理解,你要想:在之前我们调用成员方法的时候,都是使用对象去调用的,只不过以前是用 . 进行调用的,现在就是使用 :: 进行调用。

在引用成员方法的时候有三种情况需要我们知道

① 其他类:其他类对象::方法名

② 本类: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!!!

image-20240430202200123

因此如果你想要引用本类的非静态方法,那么引用处必须在非静态的方法中。

但静态方法中没有 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之后,在控制台有数据打印

image-20240430203851196

根据之前所学,我们应该给 GO 这个 JButton 添加一个点击事件。

在之前做法,是将本类 implements ActionListenergo.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() 的形参其实是一个接口

image-20240501081657384

跟进 ActionListener 看看,虽然在 ActionListener 上面没有加 @FunctionInterface,但是它本身是一个接口,里面也只有一个抽象方法,因此它也是一个函数式接口。

image-20240501081730985

既然它是函数式接口,那么就可以在 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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值