深入解析Java中的方法引用
时间:2022-06-15 [网络编程]作者:fabuyuan 浏览:3 次
推荐学习:《java视频教程》
什么是方法引用?
其实我们就从字面就开始理解,方法大家都知道,就是我们在编写代码的时候定义的方法。而方法引用就是用什么东西来引用这个方法。而引用方法说白了它的目的就是对Lambda表达式的一个进一步优化,从而减少代码的一个更简单的编写。对!你没有听错,Lambda表达式已经很优化了,那还要怎么优化呢?当我们的代码中出现了对应的类、对象、super、this的时候我们就可以使用方法引用,而这个方法引用的前提就是我们有Lambda表达式。那它是怎么样来用的呢?我们就接着往下看吧。
方法引用符
既然标题是方法引用符,什么是方法引用符呢?方法引用符就是双冒号【::】,这就是方法引用,而这也是一种新语法,是一种引用运算符,方法引用就是通过它来实现的。如果Lambda要表达的函数方案已经存在于某个方法的实现中,我们就可以通过双冒号来引用该方法实现对Lambda的代替。
注意:Lambda中传递的参数一定是方法引用中那个方法可接受的类型,否则会抛出异常。
如何使用方法引用?
方法引用可以通过以下几方面来使用:
既然是有以上几种方式的方法引用,那我们接下来就逐一进行学习一下吧。
通过对象名引用成员方法
那怎样来通过对象名引用方法呢?我们知道对象是通过类来创建的,所以我们首先要创建一个类,然后再类中定义一个成员方法,再通过类创建一个对象,用对去引用这个成员方法。
例如:
定义一个成员方法,传递字符串,把字符串按照大写输出
我们把上面的需求来实现一下吧。
先定义一个类
public class Demo02MethodRerObject { //定义一个成员方法,传递字符串,把字符串按照大写输出 public void printUpperCaseString(String s){ System.out.println(s.toUpperCase()); } }
既然是输出我们就需要打印出来,而用Lambdab就需要我们定义一个打印的函数式接口,在函数式接口中定义打印字符串的抽象方法。
/* 定义一个打印的函数式接口 */ @FunctionalInterface public interface Printable { //定义打印字符串的抽象方法 void print(String s); }
而通过对象名引用成员方法,使用前提是对象名已经存在的,成员方法也是存在的,就可以使用对象名来引用成员方法。下面我们用代码写一下:首先我们用Lambda来写一下这个需求,然后再进行用方法引用优化Lambda。
public class Demo03ObjectMethodReference { //定义一个方法,方法参数传递Printable接口 public static void pringString(Printable p){ p.print("abcde"); } public static void main(String[] args) { //pringString(System.out::print); //调用printString方法,方法的参数pringable是一个函数式接口,所以可以传递Lambda pringString((s)->{ //创建MethodRerObject对象 Demo02MethodRerObject methodRerObject=new Demo02MethodRerObject(); //调用Demo02MethodRerObject对象中的成员方法printUpperCaseString,把字符串按照大写输出 methodRerObject.printUpperCaseString(s); }); /* 使用方法引用优化Lambda 对象已经存在Demo02MethodRerObject 成员方法也是已经存在的printUpperCaseString 所以我们可以使用对象名引用成员方法 */ Demo02MethodRerObject methodRerObject=new Demo02MethodRerObject(); pringString(methodRerObject::printUpperCaseString); } }
通过类名引用静态方法
前面我们学过,我们类中有静态方法时,我们就可以通过类名来调用静态方法,而方法引用也一样,也可以通过类名来引用静态方法。下面我们同样使用代码来演示。
这次我们定义一个方法,方法的参数传递计算绝对值的整数和函数式接口Calcable。
先来定义一个接口
@FunctionalInterface public interface Calcable { //定义一个抽象方法,传递一个整数,对整数进行绝对值计算并返回 int AbsCals(int number); }
通过类名引用静态成员方法,前提是类已经存在,静态成员方法也已经存在,就可以通过类名直接引用静态成员方法。我们同样先创建类,定义方法,用Lambda编写代码,之后用方法引用优化。
public class Demo04StaticMethodReference { //定义一个方法,方法的参数传递计算绝对值的整数和函数式接口Calcable public static int method1(int number,Calcable c){ return c.AbsCals(number); } public static void main(String[] args) { //调用method方法,传递计算绝对值的整数和lambda表达式 int number=method1(-10,(n)->{ //对参数进行绝对值计算并返回结果 return Math.abs(n); }); System.out.println(number); /* 使用方法引用优化Lambdab表达式 Math类是存在的 abs计算绝对值的静态方法也是存在的 所以我们可以直接通过类名引用静态方法 */ int number2=method1(-10, Math::abs); System.out.println(number2); } }
通过super引用成员方法
提到super说明和父类方法有关,也就是有继承关系。当存在继承关系,Lambda中需要super调用时,为我们就是有是有方法引用进行代替。
定义一个见面的方法
我们使用子父类见面打招呼的方法进行演示
同样这次我们定义见面的函数式接口
/* 定义见面的函数式接口 */ @FunctionalInterface public interface Greetable { //定义一个见面的方法 void greet(); }
既然需要继承我们定义一个父类
/* 定义父类方法 */ public class Demo05Fu_Human { //定义一个sayHello的方法 public void sayHello(){ System.out.println("Hello! 我是Human。"); } }
再定义一个子类,在子类中出现父类的成员方法,先使用Lambda编写代码,再进行方法引用优化。
使用super引用父类的成员方法,前提super是已经存在的,父类的成员方法也是存在的,就可以直接使用super引用父类成员方法。
import java.nio.channels.ShutdownChannelGroupException; /* 定义子类 */ public class Demo06Zi_Man extends Demo05Fu_Human { //子类重写父类sayHello方法 @Override public void sayHello() { System.out.println("Hello!我是Man。"); } //定义一个方法,参数传递Gerrtable接口 public void method(Greetable g){ g.greet(); } public void show(){ //调用method方法,方法参数Greetable是一个函数式接口,所以可以传递Lambda表达式 method(()->{ //创建父类的Human对象 Demo05Fu_Human fHuman=new Demo05Fu_Human(); fHuman.sayHello(); }); //因为有子父类关系,所以存在的一个关键super,代表父类,可以直接使用super调用父类的成员方法 method(()->{ super.sayHello(); }); /* 使用super引用类的成员方法 super是已经存在的 父类的成员方法也是存在的 使用可以直接使用super引用父类成员方法 */ method(super::sayHello); } public static void main(String[] args) { //调用show方法 new Demo06Zi_Man().show(); } }
通过this引用成员方法
既然上面用super引用了父类的成员方法,我们之前也学过this也可以调用本类的成员方法,那同样this也可以引用本类的成员方法。
示例:
定义一个买房子的方法
同样,首先定义函数式接口。
/* 定义一个富有的函数式接口 */ @FunctionalInterface public interface Richable { //定义一个想买什么就买什么的方法 void buy(); }
然后怎么创建类,再定义买房子的方法。通过this引用成员方法,前提this是已经存在的,买房子的成员方法也是存在的,就可以直接使用this引用成员方法。同样先使用Lambda编写代码,再进行方法引用优化。
/* 通过this引用本类的成员方法 */ public class Demo07_Husband { //定义一个买房子的方法 public void buyHouse(){ System.out.println("北京二环内买一套四合院!"); } //定义一个结婚的方法,参数传递Richable接口 public void marry(Richable r){ r.buy(); } //定义一个高兴的方法 public void soHappy(){ //调用结婚的方法,方法的参数Richable是一个函数式接口,传递Lambda表达式 marry(()->{ //使用this,成员方法,调用本类买房子的方法 this.buyHouse(); }); /* 使用方法引用优化Lambda this是已经存在的 买房子的成员方法也是存在的 可以直接使用this引用成员方法 */ marry(this::buyHouse); } public static void main(String[] args) { new Demo07_Husband().soHappy(); } }
类的构造器引用
类的构造器引用也叫构造方法引用。而由于构造器名称和类名完全一样,所以构造器引用格式是这样的,类名称::new的格式表示。既然是构造器引用也就是构造方法引用,所以我们需要:
定义一个Person类。
/* person类 */ public class Person { private String name; public Person() { super(); // TODO Auto-generated constructor stub } public Person(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
然后创建一个Person对象的函数式接口
* 定义一个创建erson对象的函数式接口 */ @FunctionalInterface public interface PersonBuilder { //定义一个方法,根据传递的姓名,创建person对象返回 Person buliderPerson(String name); }
再传递一个方法,参数传递姓名和PersonBulider接口,方法中通过 姓名创建Person对象。类的构造器引用,前提构造方法new Person(String name)已知,创建对象已知 new,就可以使用Person引用new创建对象。同样先使用Lambda编写代码,再进行方法引用优化。
/* 类的构造器(构造方法)引用 */ import java.time.chrono.MinguoChronology; import javax.print.attribute.standard.PrinterName; public class Demo08Person { //传递一个方法,参数传递姓名和PersonBulider接口,方法中通过 姓名创建Person对象 public static void printName(String name,PersonBuilder pb){ Person person=pb.buliderPerson(name); System.out.println(person.getName()); } public static void main(String[] args) { //调用printName方法,方法的参数传递了函数式接口,我们可以使用Lambda表达式 printName("张三",(name)->{ return new Person(name); }); /*使用方法引用优化Lambda表达式 构造方法new Person(String name)已知 创建对象已知 new 就可以使用Person引用new创建对象*/ printName("痛而不言笑而不语的浅伤",Person::new); } }
数组的构造器引用
数组也是Object的子类,所以它也有方法引用,只是语法上稍有不同。
示例:
定义一个方法
方法的参数传递创建数组的长度和ArrayBulider接口
方法内部根据创建的长度使用ArrayBuilder中的方法创建数组并返回
同样,先创建一个数组的函数式接口
/* 定义一个创建数组的函数式接口 */ @FunctionalInterface public interface ArrayBulider { // 定义一个int类型的数组方法,参数传递数组的长度,返回创建好的int类型的数组 int[] buliderArray(int length); }
方法的参数传递创建数组的长度和ArrayBulider接口,方法内部根据创建的长度使用ArrayBuilder中的方法创建数组并返回。前提,已知创建的就是int[]数组,数组的长度也是已知的,就可以通过数组int[]引用new,根据参数传递的长度来创建数组同样先使用Lambda编写代码,再进行方法引用优化。
import java.lang.reflect.Array; import java.util.Arrays; /* 数组的构造器引用 */ public class Demo09Array_BuilderArray { /* 定义一个方法 方法的参数传递创建数组的长度和ArrayBulider接口 方法内部根据创建的长度使用ArrayBuilder中的方法创建数组并返回 */ public static int[] arrayLength(int length,ArrayBulider ab){ return ab.buliderArray(length); } public static void main(String[] args) { //调用arrayLength方法、传递数组的长度和Lambda表达式 int[]arr=arrayLength(10,(len)->{ return new int[len]; }); System.out.println(arr.length); /*使用方法引用优化Lambda表达式 已知创建的就是int[]数组 数组的长度也是已知的 就可以通过数组int[]引用new,根据参数传递的长度来创建数组*/ int[]arr1=arrayLength(5, int[]::new); System.out.println(arr1.length); System.out.println(Arrays.toString(arr1)); } }
推荐学习:《java视频教程》
以上就是深入解析Java中的方法引用的详细内容,更多请关注站长家园其它相关文章!
本文标签: java
转载请注明来源:深入解析Java中的方法引用
本文永久链接地址:https://www.adminjie.com/post/13456.html
免责声明:
本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
附:
二○○二年一月一日《计算机软件保护条例》第十七条规定:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬!鉴于此,也希望大家按此说明研究软件!
版权声明:
一、本站致力于为软件爱好者提供国内外软件开发技术和软件共享,着力为用户提供优资资源。
二、本站提供的部分源码下载文件为网络共享资源,请于下载后的24小时内删除。如需体验更多乐趣,还请支持正版。
三、我站提供用户下载的所有内容均转自互联网。如有内容侵犯您的版权或其他利益的,若有侵犯你的权益请:提交版权证明文件到邮箱 2225329873#qq.com(#换为@) 站长会进行审查之后,情况属实的会在三个工作日内为您删除。
更多精彩内容
- VUE中V-IF条件判断改变元素的样式操作
- Discuz如何解决安装时报错run_sql_error
- 低版本VS项目在VS2019无法正常编译的问题
- PHP+Redis链表解决高并发下商品超卖问题(实现原理及步骤)
- Oracle数据库的实例/表空间/用户/表之间关系简单讲解
- RSA2是啥?PHP-RSA2签名验证怎么实现?
- 华为dubal20是什么型号
- app是什么应用程序的简称
- 小程序大小超限除了分包还能怎么做?如何避免和解决大小限制?
- ana an00华为是什么型号
- 电脑显示信号线无连接是什么意思
- html5中onclick是什么意思
- 超清视效是什么意思
- vivov1818a是什么手机型号
- html5的标题标记一共有几个等级

- 最新文章
-
-
php中restful风格是什么意思
php中restful风格指的是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义;RESTFUL适用于移动互联网厂商...
-
php中preg_replace怎么替换变量数据
在php中,“preg_replace”函数可以执行一个正则表达式的搜索和替换来替换变量数据,语法为“preg_replace(规定搜索的模式,用于替换的字符串...
-
vue抽象语法树和虚拟dom的区别是什么
vue抽象语法树和虚拟dom的区别:1、抽象语法树指的是源代码语法结构的一种抽象表示,而虚拟dom本质上就是一个普通的JS对象,用于描述视图的界面结构;2、虚拟...
-
vue3和vue2的语法有什么区别
vue3和vue2的语法区别:1、vue2使用的是webpack形式去构建项目,而vue3使用vite构建项目;2、vue2中可以使用pototype的形式去进...
-
66个面试问题,带你梳理MySQL知识点!数据库架构存储引擎日志SQL 优化索引锁事务高可用/性能运维
作为SQLBoy,基础部分不会有人不会吧?面试也不怎么问,基础掌握不错的小伙伴可以跳过这一部分。当然,可能会现场写一些SQL语句,SQ语句可以通过牛客、Lee...
-
- 热门文章
-
-
VUE中V-IF条件判断改变元素的样式操作
这篇文章主要介绍了VUE中V-IF条件判断改变元素的样式操作,具有很好的参考价值,希望对大家有所帮助。一起跟随想过来看看吧...
-
Discuz如何解决安装时报错run_sql_error
问题环境VMware虚拟机Centos7.3PHP7.0MySQL8.0NGINX1.14Discuz3.4问题还原本地环境为PHP5.6+MySQL5.6在安...
-
低版本VS项目在VS2019无法正常编译的问题
低版本VS项目在VS2019无法正常编译的问题这里指的编译并不准确,只是为了方便说明。后有(未安装),201?...
-
PHP+Redis链表解决高并发下商品超卖问题(实现原理及步骤)
实现原理使用redis链表来做,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用。实现步骤第一步,先将商品库存入队列/**.trigge...
-
Oracle数据库的实例/表空间/用户/表之间关系简单讲解
完整的Oracle数据库通常由两部分组成:Oracle数据库和数据库实例。Oracle是一种数据库管理系统,是一种关系型的数据库管理系统。我们用这些高级权限账号...
-