java中的方法引用
目录
简介
一,类::静态方法
二,对象::实例方法
三,类::实例方法
四,构造器引用,Class::new
五,数组引用,数组::new
简介
从JDK1.8开始,可以使用方法引用。
方法引用的操作符是双冒号"::"。
方法引用可以认为是Lambda表达式的一种特殊形式,Lambda表达式可以让开发者自定义抽象方法的实现代码,方法引用则可以让开发者直接引用已存在的实现方法,作为Lambda表达式的Lambda体(参数列表得一致)。
先写一个简单的Lambda表达式的例子作为对比:
@FunctionalInterface
public interface ImTheOne {String handleString(String a, String b);
}public class Test {public static void main(String[] args) {ImTheOne theOne = (a, b) -> a + b;String result = theOne.handleString("abc", "def");System.out.println(result);}
}
Lambda体的内容是两个字符串连接,下面列举几个方法引用的实例。
方法引用的几种形式:
一,类::静态方法
如果我们打算把一个类中的静态方法作为Lambda体,可以这样用:
@FunctionalInterface
public interface ImTheOne {String handleString(String a, String b);
}
class OneClass {public static String concatString(String a, String b) {return a + b;}
}public class Test {public static void main(String[] args) {ImTheOne theOne = OneClass::concatString;String result = theOne.handleString("abc", "def");System.out.println(result);//相当于以下效果,直接把类的静态方法写在Lambda体里ImTheOne theOne2 = (a, b) -> OneClass.concatString(a, b);String result2 = theOne2.handleString("123", "456");System.out.println(result2);}
}
在这段代码中,把OneClass类的concatString()方法作为了Lambda表达式的Lambda体。
效果和Lambda表达式相同,当调用接口的handleString()方法时,调用的实际上是OneClass类的concatString()方法。
注意:
1,OneClass类的concatString()方法的参数列表,和ImTheOne接口的handleString()方法参数列表必须一致,才能用方法引用,否则编译报错。
2,此时的concatString()方法必须标记为静态方法,否则编译会报错。
二,对象::实例方法
我们可以把一个实例的非静态方法作为Lambda体,比如这样:
@FunctionalInterface
public interface ImTheOne {String handleString(String a, String b);
}
class OneClass {public String concatString(String a, String b) {return a + b;}
}public class Test {public static void main(String[] args) {OneClass oneClass = new OneClass();ImTheOne theOne = oneClass::concatString;String result = theOne.handleString("abc", "def");System.out.println(result);//相当于以下效果OneClass oneClass2 = new OneClass();ImTheOne theOne2 = (a, b) -> oneClass2.concatString(a, b);String result2 = theOne2.handleString("123", "456");System.out.println(result2);}
}
这段代码中,先定义了OneClass的一个对象,然后把对象的concatString()方法作为Lambda体。
注意:
1,这种模式下, concatString()方法不能标记为静态方法,否则编译会报错。
2,这里的对象可以是父对象,比如可以使用:
super:: concatString
这种形式(如果有父类有这个方法的话)。
三,类::实例方法
这种模式并不是要直接调用类的实例方法,这样显然连编译都过不去。
这种模式实际上是 对象::实例方法模式的一种变形,当一个对象调用方法时,方法的某个参数是函数式接口,而且函数式接口的方法参数列表的第一个参数就是调用者对象所属的类时,可以引用调用者类中定义的,不包含函数式接口第一个参数的方法,并用类::实例方法这种形式来表达,比如这样:
@FunctionalInterface
public interface ImTheOne<T> {String handleString(T a, String b);
}
class OneClass {String oneString;public String concatString(String a) {return this.oneString + a;}public String startHandleString(ImTheOne<OneClass> imTheOne, String str) {String result = imTheOne.handleString(this, str);return result;}
}public class Test {public static void main(String[] args) {OneClass oneClass = new OneClass();oneClass.oneString = "abc";String result = oneClass.startHandleString(OneClass::concatString, "123");System.out.println(result);//相当于以下效果OneClass oneClass2 = new OneClass();oneClass2.oneString = "abc";ImTheOne theOne2 = (a, b) -> oneClass2.concatString(b);String result2 = theOne2.handleString(theOne2, "123");System.out.println(result2);}
}
输出的结果是:
abc123456
abc123456
对这种模式的理解大概是这样的:
当一个对象调用一个方法,方法的参数中包含一个函数式接口,该函数式接口的第一个参数类型是这个对象的类,那么这个函数式接口可用方法引用代替,并且替换用的方法可以不包含函数式接口的第一个参数(调用对象的类)。
看起来比较绕,下面画个表对照代码具体解释一下:
步骤 | 描述 | 代码对照 |
1 | 当一个对象调用一个方法 | oneClass对象,调用startHandleString(ImTheOne<OneClass> imTheOne, String str)方法。 |
2 | 方法的参数中包含一个函数式接口 |
startHandleString方法中有个参数是ImTheOne<OneClass>, ImTheOne<T>是一个函数式接口,在本例中使用的泛型是OneClass类。 |
3 | 该函数式接口的第一个参数类型是这个对象的类 |
ImTheOne<T>这个函数式接口的唯一抽象方法是handleString(T t, String a, String b), 第一个参数就是ImTheOne定义时的泛型类,也就是OneClass类,也就是步骤1时调用者oneClass对象所属的类。 |
4 | 那么这个函数式接口可用方法引用代替 | 对于ImTheOne<OneClass>这个参数,可以用OneClass::concatString这个方法引用来代替。 |
5 | 并且替换用的方法可以不包含函数式接口的第一个参数 |
函数式接口中的handleString方法参数列表是 (T t, String a, String b),3个参数,而方法引用中的concatString方法参数是(String a, String b),比handleString少了第一个T参数, 此时java会认为第一个参数就是方法的调用者oneClass对象。 |
另外,这种模式下方法引用的方法必须是调用者对象所属类中的对象,也就是concatString方法必须定义在OneClass类中。
四,构造器引用,Class::new
这种模式被称为构造方法引用,或构造器引用。
构造方法也是方法,构造方法引用实际上表示一个函数式接口中的唯一方法引用了一个类的构造方法,引用的是那个参数相同的构造方法。
下面举个例子:
@FunctionalInterface
public interface ImTheOne {TargetClass getTargetClass(String a);
}
class TargetClass {String oneString;public TargetClass() {oneString = "default";}public TargetClass(String a) {oneString = a;}
}public class Test {public static void main(String[] args) {ImTheOne imTheOne = TargetClass::new;TargetClass targetClass = imTheOne.getTargetClass("abc");System.out.println(targetClass.oneString);//相当于以下效果ImTheOne imTheOne2 = (a) -> new TargetClass("abc");TargetClass targetClass2 = imTheOne2.getTargetClass("123");System.out.println(targetClass2.oneString);}
}
注意:
1,函数式接口的方法getTargetClass(String a)有一个String类型的参数,所以当使用构造方法引用时,引用的是有一个String参数的那个构造,也就是这个:
public TargetClass(String a) {oneString = a;
}
2,本例输出的结果是:
abc
abc
注意到第二行输出的不是123,而是abc,因为Lambda表达式的原因,当我们执行:
imTheOne2.getTargetClass("123");
这行代码时,调用的实际上是Lambda体:
new TargetClass("abc");
所以输出的结果和字符串"123"没关系。
五,数组引用,数组::new
数组引用算是构造器引用的一种,可以引用一个数组的构造,举个例子:
@FunctionalInterface
public interface ImTheOne<T> {T getArr(int a);
}
public class Test {public static void main(String[] args) {ImTheOne<int[]> imTheOne = int[]::new;int[] stringArr = imTheOne.getArr(5);System.out.println(stringArr.length);}
}
注意:
使用数组引用时,函数式接口中抽象方法必须是有参数的,而且参数只能有一个,必须是数字类型int或Integer,这个参数代表的是将来生成数组的长度。
以上
java中的方法引用相关推荐
- Java 8 中的方法引用,轻松减少代码量,提升可读性!
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 1. 引言 Java8中最受广大开发中喜欢的变化之一是因为 ...
- 你知道Java 8 的方法引用吗
1. 前言 Java中的方法引用,很多同学都见过但却叫不出名字甚至不太会用,在这篇文章中,我们将看到什么是方法引用以及如何使用它. 2. 方法引用的使用场景 我们先来看看方法引用的使用: new Ra ...
- 理解Java中的弱引用(Weak Reference)
理解Java中的弱引用(Weak Reference) 本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限, ...
- java中同步_在Java中的方法同步和语句同步(块同步) - Break易站
Java 多线程 线程主要通过共享对字段的访问和参考字段引用的对象进行通信.这种通信形式非常有效,但可能出现两种错误:线程干扰和内存一致性错误.需要一些同步构造来防止这些错误.以下示例显示了我们需要同 ...
- java的弱引用_深入理解Java中的弱引用
不久之前,我面试了一些求职Java高级开发工程师的应聘者.我常常会面试他们说,"你能给我介绍一些Java中得弱引用吗?",如果面试者这样说,"嗯,是不是垃圾回收有关的?& ...
- java弱引用怎么手动释放,十分钟理解Java中的弱引用,十分钟java引用
十分钟理解Java中的弱引用,十分钟java引用 本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,帮助大家理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限 ...
- Java中对象和引用的理解
2019独角兽企业重金招聘Python工程师标准>>> 偶然想起Java中对象和引用的基本概念,为了加深下对此的理解和认识,特地整理一下相关的知识点,通过具体实例从两者的概念和区别两 ...
- Java中的方法(形参及实参)return返回类型
如何定义 Java 中的方法 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 一般情况下,定义一个方法的语法是: 其中: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 pub ...
- Java中equals()方法和==的区别分析
Java中equals方法和==的区别分析 equals(Object obj)方法,将对象与传入的obj进行比较,相等返回true,否则返回false.equals方法和"==" ...
最新文章
- java 判断是否是list_给Java程序员的20个链表面试题
- RAID重组和数据库数据的修复与验证
- 概念辨析:工厂模式 工厂方法模式 简单工厂模式 抽象工厂
- MySQL 面试必备:又一神器“锁”,不会的在面试都挂了
- loadrunner代理录制脚本方法介绍
- java线程的创建线程_多线程(Thread、线程创建、线程池)
- 打印python包含汉字报SyntaxError: Non-ASCII character '\xe4' in file
- 安卓加密软件_(安卓)微信聊天加密软件
- php socket 超时设置
- jQuery获取iframe中页面的高度
- 【企鹅电竞直播源】浏览器抓取真实直播源地址(纯前端JS PHP解析源码)
- 既是手机直播投屏工具又是安卓模拟器?游戏主播和手游玩家都来了解一下
- 什么是数字证书?它有什么作用?
- 批量微信号码过滤程序
- 【数学和算法】加权平均法
- H5前端实现微信分享(处理二次分享问题)
- windows10升级助手_Win7即将全面停更,看这里,决定回退还是升级?
- c语言编程入门教程+网易,人话讲编程·C语言入门:第一讲,Hello World
- RDLC报表打印尺寸不匹配的问题
- model(**inputs)备忘
热门文章
- R-xts()时间序列
- Cleanmymac X绿色中文苹果系统清理软件
- 普法 | 如果你被裁员,赔偿金是N、N+1、2N呢?
- mysql哪些查询情况不走索引
- 编译原理(文法、符号表)
- Java基础入门必备词汇汇
- 用户触达方式及用户触达渠道选择
- Milestone 如何突破疫情封锁,准时发布 MotoGP™20
- 使用canvas截图跨域导致的报错(Failed to execute ‘toDataURL‘ on ‘HTMLCanvasElement)
- hdu 1078 FatMouse Chees