【JAVA入门】Day35 - 方法引用

2024-09-08 04:04
文章标签 java 方法 入门 引用 day35

本文主要是介绍【JAVA入门】Day35 - 方法引用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【JAVA入门】Day35 - 方法引用


文章目录

  • 【JAVA入门】Day35 - 方法引用
    • 一、方法引用的分类
      • 1.引用静态方法
      • 2.引用成员方法
        • 2.1 引用其他类的成员方法
        • 2.2 引用本类和父类的成员方法
        • 2.3 引用构造方法
        • 2.4 使用类名引用成员方法
        • 2.5 引用数组的构造方法
    • 二、方法引用的例题


        方法引用就是“把已经有的方法当作函数式接口中抽象方法的方法体”来使用。

        下面是一个排序方法,它的第二个参数是一个 Comparator 接口的实现类,它是一个函数式接口,因此我们可以用方法引用改写这段代码。

Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}
});

        直接将已经存在的方法作为第二个参数。

public int subtraction(int n1, int n2) {return n2 - n1;
}Arrays.sort(arr, 比较规则 );

        要使用方法引用有一些限制:

  • 最重要的限制是,引用处必须是一个函数式接口,是可以把接口实现类作为参数传递的。
  • 对于被引用的方法有以下三个限制:
    1.被引用的方法必须已经存在了。
    2.被引用的方法的形参返回值需要跟抽象方法保持一致。
    3.被引用的方法的功能要满足当前需求。

        以下面这段代码为例,我们将演示方法引用相较于之前方法的简洁性。

package Functions;import java.util.Arrays;
import java.util.Comparator;public class FunctionDemo1 {public static void main(String[] args) {//需求:创建一个数组,进行倒序排序Integer[] arr = {3,5,4,1,6,2};//匿名内部类Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});//lambda表达式Arrays.sort(arr, (Integer o1, Integer o2) -> {return o2 - o1;});//lambda表达式简化格式Arrays.sort(arr, (o1, o2) -> o2 - o1);//方法引用//表示引用FunctionDemo1类里面的subtraction方法//把这个方法当作抽象方法的方法体Arrays.sort(arr, FunctionDemo1::subtraction);System.out.println(Arrays.toString(arr));}//被引用的方法可以是Java已经写好的,也可以是一些第三方工具类public static int subtraction(int num1, int num2) {return num2 - num1;}
}

一、方法引用的分类

        方法引用一般就分为三大类:引用静态方法、引用成员方法(这个分为引用其他类的成员方法、引用本类的成员方法、引用父类的成员方法)、引用构造方法。但是也有其他调用方式,比如:使用类名引用成员方法、引用数组的构造方法。

1.引用静态方法

格式:

类名::静态方法

范例:

Integer::parseInt

【练习】集合中有“1”“2”“3”“4”“5”五个字符串数字,要求把他们变成 int 类型。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;public class FunctionDemo2 {public static void main(String[] args) {/*集合中有“1”“2”“3”“4”“5”五个字符串数字,要求把他们变成 int 类型。*///1.创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "1","2","3","4","5");//2.常规方式ArrayList<Integer> list2 = new ArrayList<>();for (String s : list) {int i = Integer.parseInt(s);list2.add(i);}//3.方法引用
/*        list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}}).forEach(s -> System.out.println(s));*///1.方法需要已经存在//2.方法的形参和返回值需要跟抽象方法的形参和返回值保持一致//3.方法的功能需要把形参的字符串转换成整数//引用的是Integer方法中的pareInt()方法list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s));}
}

2.引用成员方法

格式:

对象::成员方法

① 其他类:

其他类对象::方法名

② 本类:

this::方法名

③ 父类:

super::方法名
2.1 引用其他类的成员方法
package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;public class FunctionDemo3 {public static void main(String[] args) {/*只要以张开头的,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据//完整写法
/*        list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s -> System.out.println(s));*///方法引用写法//引用其他类的成员方法//已知有另一个类StringOperation中有同样功能方法//成员方法需要创建对象来使用,因此要先创建StringOperation类对象StringOperation so = new StringOperation();list.stream().filter(so::stringJudge);}
}
2.2 引用本类和父类的成员方法

        要注意,要引用本类成员方法时,若引用处位于 main() 方法中,它是一个静态方法,静态方法是没有 this 和 super 变量的,因此这里就只能先创建好本类的对象再进行调用。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;public class FunctionDemo3 {public static void main(String[] args) {/*只要以张开头的,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据//完整写法
/*        list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s -> System.out.println(s));*///方法引用写法//引用本类的成员方法//已知本类中有同样功能方法//成员方法需要创建对象来使用,因此要先创建本类对象list.stream().filter(new FunctionDemo3()::stringJudge);}public boolean stringJudge(String s) {return s.startsWith("张") && s.length() == 3;}
}

        因此,想要使用 this 和 super,就要在一个非静态方法中,如下面的例子:
        下面的例子中,我们创建了一个窗体,自己在本类中写了一个按钮的事件监听方法,并作为参数传给了按钮的addActionListener()方法,这里就是使用了本类的方法引用,这样做使得该窗体无需实现 ActionListener 接口也能自己实现按钮点击的事件逻辑。

package Functions;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;public class LoginJFrame extends JFrame {//创建一个按钮,点击按钮打印一句话JButton go = new JButton("Go");public LoginJFrame() {//初始化界面initJFrame();//添加组件initView();//显示界面this.setVisible(true);}//设置界面public void initJFrame() {//设置宽高this.setSize(400,500);}//添加组件public void initView() {go.setBounds(120,274,150,50);this.getContentPane().add(go);//给按钮添加点击事件//该方法形参是一个函数式接口//因此可以在此处使用方法引用//此时在本类可以自己写一个按钮监听的方法操作,作为方法引用,使用this::method传入//这样可以使得该窗体不必实现ActionListener接口也能实现按钮的点击事件go.addActionListener(this::method);}//自己写的按钮监听方法public void method(ActionEvent e){Object obj = e.getSource();if(obj == go){System.out.println("go按钮被点击了");}}
}

        下面的例子中,我们让一个窗体继承了一个 MyJFrame 类,再让 MyJFrame 类继承自 JFrame,然后我们在 MyJFrame 类中自己编写了一个事件监听方法 method,然后在 MyJFrame 类中让按钮的 addActionListener() 方法引用 MyJFrame 类中的事件监听方法 method,这样就实现了引用自父类的成员方法。

父类 MyJFrame:

package Functions;import javax.swing.*;
import java.awt.event.ActionEvent;//注意形参和原方法保持一致
public class MyJFrame extends JFrame {public void method(ActionEvent e){System.out.println("go按钮被点击了");}
}

子类 LoginJFrame:

package Functions;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;public class LoginJFrame extends MyJFrame {//创建一个按钮,点击按钮打印一句话JButton go = new JButton("Go");public LoginJFrame() {//初始化界面initJFrame();//添加组件initView();//显示界面this.setVisible(true);}//设置界面public void initJFrame() {//设置宽高this.setSize(400,500);}//添加组件public void initView() {go.setBounds(120,274,150,50);this.getContentPane().add(go);//给按钮添加点击事件//该方法形参是一个函数式接口//因此可以在此处使用方法引用//此时在父类可以自己写一个按钮监听的方法操作,作为方法引用,使用super::method传入go.addActionListener(super::method);}
}

        由上面的例子可以看出,方法引用可以代替函数式接口作为方法的参数传递,利用方法引用可以调整代码结构,省去实现多余的接口。

2.3 引用构造方法

        我们引用构造方法就是为了创建对象。

格式:

类名::new

范例:

Student::new

        以下面的例子为讲解,我们为什么要引用构造方法。
        首先我们在 Student 类中重载了一个构造方法,它是为了适配构造方法引用而设的。

package Functions;import java.util.Objects;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}//用方法引用,在Student类中重载构造方法,按照上面的public Student apply(String s)的方法体重写//str表示流里面的每一个数据public Student(String str){this.name = str.split("-")[0];this.age = Integer.parseInt(str.split("-")[1]);}}

        然后我们在测试类中引用构造方法,代替了原来的 map 方法中的函数式接口重写的方法 apply。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;public class FunctionDemo4 {/*集合里存储姓名和年龄,比如:张无忌,15要求:将数据封装成Student对象并收集到List集合中*/public static void main(String[] args) {//1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41");//3.封装成Student对象并收集到List集合中//String --> Student/*        //用map方法List<Student> newList = list.stream().map(new Function<String, Student>() {@Overridepublic Student apply(String s) {return new Student(s.split("-")[0], Integer.parseInt(s.split("-")[1]));}}).collect(Collectors.toList());*///用方法引用,在Student类中重载构造方法,按照上面的public Student apply(String s)的方法参数和功能重写//构造方法没有返回值,只要保证重载的构造方法对象和你原方法返回的对象保持一致即可List<Student> newList = list.stream().map(Student::new).collect(Collectors.toList());}
}

        这里要注意的就是,构造方法生成的对象,要和原来方法你要求返回的对象一致(姓名、年龄的格式),且构造方法的参数必须和原方法保持一致(String s)。

2.4 使用类名引用成员方法

        直接用类名引用成员方法。
格式:

类名::成员方法

范例:

String::substring

【练习】集合里有一些字符串,要求变成大写后进行输出。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;public class FunctionDemo5 {public static void main(String[] args) {/*集合里有一些字符串,要求变成大写后进行输出。类名::成员方法规则:1.需要有函数式接口2.被引用的方法必须已经存在3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致4.被引用的方法功能要满足当前需求抽象方法形参的详解:第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法(比如第一个参数是String类型,那么只能引用String类中的方法)在Stream流当中,第一个参数一般都表示流里面的每一个数据假设流里面的数据是字符串,那么使用这种方式进行方法调用,只能引用String这个类中的方法第二个参数到最后一个参数:跟被引用的方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法*///1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");//3.变成大写//String --> String
/*        list.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toUpperCase();}}).forEach(s -> System.out.println(s));*///拿流里面的每一个数据,去调用String类中的toUpperCase()方法,方法的返回值就是转换之后的字符串list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));}
}

这种方法有一定的局限性:

1.它不能引用所有类中的成员方法。
2.它能引用的类中的成员方法,取决于它的抽象方法(上面代码中的 apply(String s))的第一个参数类型,这个参数是什么类型,它就只能引用这个类中的方法。
3.如果这个抽象方法(apply(String s))没有第二个及以后的参数,那么它就可以引用一个类中的空参方法。

2.5 引用数组的构造方法

格式:

数据类型[]::new

范例:

Integer[]::new

【练习】集合中存储一些整数,然后收集到数组当中。

package Functions;import java.util.ArrayList;
import java.util.Collections;
import java.util.function.IntFunction;public class FunctionDemo6 {public static void main(String[] args) {/*细节:数组的类型,需要跟流中的数据的类型保持一致*///1.创建集合ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);//2.收集到数组当中
/*        Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});*///此时会将流中每一个数据存入生成的数组中list.stream().toArray(Integer[]::new);}
}

二、方法引用的例题

【练习1】集合中存一些字符串,比如:张三,23。收集到Student数组当中。

package Functions;import JavaStudy1.Array.Array;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;public class FuntcionTest1 {public static void main(String[] args) {/*集合中存一些字符串,比如:张三,23。收集到Student数组当中。*///1.创建集合添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41");//2.先把字符串变成Student对象,然后再把Student对象收集起来//String --> StudentStudent[] arr = list.stream().map(Student::new).collect(Collectors.toList()).toArray(Student[]::new);System.out.println(Arrays.toString(arr));}
}

【练习2】创建集合并添加学生对象,要求获取姓名放到数组中。

package Functions;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class FunctionTest2 {public static void main(String[] args) {/*创建集合并添加学生对象,要求获取姓名放到数组中。"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-41"*///1.创建集合添加数据ArrayList<Student> list = new ArrayList<>();Collections.addAll(list, new Student("张无忌",15),new Student("周芷若",14),new Student("赵敏",13),new Student("张强",20),new Student("张三丰",100),new Student("张翠山",40));//2.把姓名获取出来生成字符串数组//Student --> StringString[] arr = list.stream().map(Student::getName).toArray(String[]::new);System.out.println(Arrays.toString(arr));}
}

【练习3】创建集合添加学生对象,把姓名和年龄拼成:张三-23的字符串,并放到数组当中。

package Functions;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;public class FunctionTest3 {public static void main(String[] args) {/*创建集合添加学生对象,把姓名和年龄拼成:张三-23的字符串,并放到数组当中。*///1.创建集合并添加学生对象ArrayList<Student> list = new ArrayList<>();Collections.addAll(list, new Student("张无忌",15),new Student("周芷若",14),new Student("赵敏",13),new Student("张强",20),new Student("张三丰",100),new Student("张翠山",40));//2.取出姓名和年龄拼成字符串//Student --> StringString[] arr = list.stream().map(Student::toString).toArray(String[]::new);System.out.println(Arrays.toString(arr));}
}

这篇关于【JAVA入门】Day35 - 方法引用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147063

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象