Java学习:方法的引用
方法引用(Method references)
lambda表达式允许我们定义一个匿名方法,并允许我们以函数式接口的方式使用它。我们也希望能够在已有的方法上实现同样的特性。
方法引用和lambda表达式拥有相同的特性(例如,它们都需要一个目标类型,并需要被转化为函数式接口的实例),不过我们并不需要为方法引用提供方法体,我们可以直接通过方法名称引用已有方法。
以下面的代码为例,假设我们要按照name或age为Person数组进行排序:
class Person {
private final String name;
private final int age;
public int getAge() { return age; }
public String getName() {return name; }
...
}
Person[] people = ...
Comparator<Person> byName = Comparator.comparing(p -> p.getName());
Arrays.sort(people, byName);
在这里我们可以用方法引用代替lambda表达式:
Comparator<Person> byName = Comparator.comparing(Person::getName);
这里的Person::getName可以被看作为lambda表达式的简写形式。尽管方法引用不一定(比如在这个例子里)会把语法变的更紧凑,但它拥有更明确的语义——如果我们想要调用的方法拥有一个名字,我们就可以通过它的名字直接调用它。
因为函数式接口的方法参数对应于隐式方法调用时的参数,所以被引用方法签名可以通过放宽类型,装箱以及组织到参数数组中的方式对其参数进行操作,
就像在调用实际方法一样:
Consumer<Integer> b1 = System::exit; // void exit(int status)
Consumer<String[]> b2 = Arrays:sort; // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)
Runnable r = Myprogram::mapToInt // void main(String... args)
方法引用的种类(Kinds of method references)
方法引用有很多种,它们的语法如下:
- 静态方法引用:ClassName::methodName
- 实例上的实例方法引用:instanceReference::methodName
- 超类上的实例方法引用:super::methodName
- 类型上的实例方法引用:ClassName::methodName
- 构造方法引用:Class::new
- 数组构造方法引用:TypeName[]::new
对于静态方法引用,我们需要在类名和方法名之间加入::分隔符,例如Integer::sum。
对于具体对象上的实例方法引用,我们则需要在对象名和方法名之间加入分隔符:
Set<String> knownNames = ...
Predicate<String> isKnown = knownNames::contains;
这里的隐式lambda表达式(也就是实例方法引用)会从knownNames中捕获String对象,而它的方法体则会通过Set.contains使用该String对象。
有了实例方法引用,在不同函数式接口之间进行类型转换就变的很方便:
Callable<Path> c = ...
Privileged<Path> a = c::call;
引用任意对象的实例方法则需要在实例方法名称和其所属类型名称间加上分隔符:
Function<String, String> upperfier = String::toUpperCase;
这里的隐式lambda表达式(即String::toUpperCase实例方法引用)有一个String参数,这个参数会被toUpperCase方法使用。
如果类型的实例方法是泛型的,那么我们就需要在::分隔符前提供类型参数,或者(多数情况下)利用目标类型推导出其类型。
需要注意的是,静态方法引用和类型上的实例方法引用拥有一样的语法。编译器会根据实际情况做出决定。
一般我们不需要指定方法引用中的参数类型,因为编译器往往可以推导出结果,但如果需要我们也可以显式在::分隔符之前提供参数类型信息。
和静态方法引用类似,构造方法也可以通过new关键字被直接引用:
SocketImplFactory factory = MySocketImpl::new;
- 如果类型拥有多个构造方法,那么我们就会通过目标类型的方法参数来选择最佳匹配,这里的选择过程和调用构造方法时的选择过程是一样的。
- 如果待实例化的类型是泛型的,那么我们可以在类型名称之后提供类型参数,否则编译器则会依照"菱形"构造方法调用时的方式进行推导。
数组的构造方法引用的语法则比较特殊,为了便于理解,你可以假想存在一个接收int参数的数组构造方法。
参考下面的代码:
IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10) // 创建数组 int[10]
Java学习:方法的引用的更多相关文章
- Java学习--方法
Java学习 方法 方法 定义 Java方法是语句的集合,一起执行一个功能. 方法是解决一类问题的步骤的有序组合. 方法包含在类或对象中. 方法在程序中被创建,在其他地方被引用. 设计方法的时候,最好 ...
- Java学习——方法
在这一次的学习中我觉得首先要了解: 什么是方法呢 方法又怎么定义与调用 上面这段代码是我们经常写到的,其实它就是一个方法,其中 public 是修饰符 void是返回值类型 main就是方法名 arg ...
- Java学习之一(引用相关)
1.Java概述 首先,Java是一门面向对象的编程语言.相对于C/C++等语言,Java中没有指针,但是这不代表指针等知识不重要:Java中不存在多继承但是存在多接口.在我自己的学习过程之中,我偏向 ...
- Java学习----方法的重载
一个类中有多个同名的参数不一样的方法. 作用:可以根据不同的条件调用不同的方法. 注意:java不会因为方法的返回类型或者权限的不同而判断为不同的两个方法. public class Student ...
- Java学习---- 数组的引用传递
1. public class ArrayRefDemo01{ public static void main(String args[]){ int temp[] = {1,3,5} ; // 利用 ...
- Java学习笔记day03_引用数据类型
1.引用数据类型 步骤: 1. 导包 2. 创建引用类型变量 类型 变量名 = new 类型名(); 3. 使用数据类型的功能 变量名.功能名(); 如Scanner类: import jav ...
- Java学习----方法的覆盖
方法的覆盖:子类继承父类,子类重写父类的同名方法. 覆盖的原则: 1. 方法的参数必须跟父类保持一致 2. 子类方法的修饰符的范围必须大于等于父类方法同名的修饰符(public > privat ...
- Java学习——方法中传递参数分简单类型与复杂类型(引用类型)编程计算100+98+96+。。。+4+2+1的值,用递归方法实现
package hello; public class digui { public static void main(String[] args) { // TODO Auto-generated ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
随机推荐
- maven 学习---Maven添加远程仓库
默认情况下,Maven从Maven中央仓库下载所有依赖关系.但是,有些库丢失在中央存储库,只有在Java.net或JBoss的储存库远程仓库中能找到. 1. Java.net资源库 添加Java.ne ...
- 如何在unbuntu 16.04上在线安装vsftpd
本文涉及命令如下: # service vsftpd status //查询vsftp服务状态 # apt-get remove vsftpd //卸载vsftpd # apt-get install ...
- oracle查询中会使索引无效的情况总结
总结一下oracle中会使索引无效的情况 1 无where条件: 2 索引列进行运算时: 3 使用like,并且通配符在前的情况: 4 字符型字段为数字时在where条件里不添加引号: 5 not i ...
- java引用的强制转型
在java的面向对象的特性里,父类的引用可以指向子类的实例对象.但是,如果一个引用b(b本身指向了一个对象)想赋值给引用a,b不是a的类型且不是a的子类类型,那么就需要强制转换,并有失败的可能性,这个 ...
- css实现简单音乐符效果
css实现简单音乐符效果 利用css3中的transform.animation.keyframes实现 <!DOCTYPE html> <html lang="en&qu ...
- Python获取帮助的3种方式(转载)
我们可以很容易的通过Python解释器获取帮助.如果想知道一个对象(object)更多的信息,那么可以调用help(object)!另外还有一些有用的方法,dir(object)会显示该对象的大部分相 ...
- pycharm访问mysql数据库
不需要像eclipse那样添加驱动包,在pycharm里面下载一个pymysql包即可. 然后链接自己电脑的mysql并进行访问即可. 源码如下(参考博客:https://blog.csdn.net/ ...
- vue系列---Vue组件化的实现原理(八)
_ 阅读目录 一. 什么是Vue组件? 如何注册组件? 1.1 全局注册组件 1.2 局部注册组件 二:组件之间数据如何传递的呢? 1) props 2) $emit 3) 使用$ref实现通信 4) ...
- redixdb 基于redis 协议的实时key-value 存储
redixdb 是一个基于redis 协议搞的一个实时key value 处理的轻量级应用,支持多种后端 存储模型. 以下是一个小版的容器镜像(官方的太大了) dockerfile FROM go ...
- SWA2G422&485JK2G基础篇: STM32+W5500实现MQTT通信控制,485/422透传通信
说明 这节实现的功能: STM32+W5500实现MQTT通信控制 细节功能: 1.DHCP动态获取IP 2.DNS域名解析 3.网口<--MQTT-->485/422透传通信 测试准备工 ...