Java – 方法引用
方法引用简介
方法引用,指的是,当你需要编写某种功能方法时,恰好别的地方有这么一个方法,和你想要编写的功能完全相同,那么我们就可以直接引用这个方法,让别人的方法计算给出结果,来代替我们自己写的方法。
方法引用需要特定的符号,Java 中使用 双冒号 ::
来指定某个类的某个方法。
方法引用时要注意:
1.调用方法者,需要有函数式接口(即接口中有且仅有一个实现方法)
2.被引用的方法必须已经存在
3.被引用的方法的形参和返回值需要和接口实现方法的形参和返回值一致
4.被引用方法的功能要满足当前的需求(即确实有用才行)
方法引用使用
定义一个List,使它们倒序排列
ArrayList<Integer> ints2 = new ArrayList<>();
Collections.addAll(ints2,3,21,6,2,54,6);
// 需求,实现他们倒向排序??
使用匿名内部类实现
ints2.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
使用Lambda方法实现
ints2.sort((o1, o2) -> o2 - o1);
使用方法引用实现
首先,我们必须有能实现接口方法的第三方方法,我们先定义一个第三方的方法
// 假设我们或别人在以前已经开发了这样一个类和方法
// 且这个方法,它的返回值,和接收的参数与排序的接口实现方法一样
class NumberMin {
public static int numMin(int m1, int m2) {
return m2 - m1;
}
}
那么我们就可以利用这个方法,来代替我们的接口实现方法
使用格式是:
类 :: 方法名
通过方法引用,实现接口方法如下
// 通过调用 NumberMin :: numMin 来指定 NumberMin 类的 numMin 方法
// 来代替我们的实现接口的方法
ints2.sort(NumberMin::numMin);
引用方法分类
引用静态方法
使用 类 :: 静态方法
来实现引用别的类的静态方法,满足接口方法实现
示例:
ArrayList<String> strNum = new ArrayList<>();
Collections.addAll(strNum,"1","2","3","4","5");
// 需求:把集合中的字符转成 int 类型???
我们可以通过增强for 等方式遍历所有集合,并转成 int 类型
for (String s : strNum) {
int i = Integer.parseInt(s);
}
也可以通过 Stream().map() 方法实现类型转换
strNum.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
});
此时我们发现,有那么一个方法,和我们的需求比较相似,那就是 Integer.parseInt()
方法,此时我们就可以利用方法引用,利用 Integer.parseInt()
方法来满足我们的实现接口方法
strNum.stream().map(Integer::parseInt);
Integer.parseInt()
会代替我们的 接口方法 来完成我们想要的功能。
引用成员方法
引用其它类的对象成员方法
语法:实例对象 :: 对象方法
比如某对象中也存在这么一个方法(非静态),也可以通过利用对象的方法进行方法引用
NumberMin nm = new NumberMin();
strNum.stream().map(nm :: numMin)
或者直接 new 完之后,进行引用
strNum.stream().map(new NumberMin() :: numMin)
引用本类的成员方法
语法:this :: 成员方法
strNum.stream().map(this :: numMin);
public int numMin(int m1, int m2) {
return m2 - m1;
}
引用父类的成员方法
语法:super :: 对象方法
strNum.stream().map(super :: numMin);
public int numMin(int m1, int m2) {
return m2 - m1;
}
引用类的成员方法
上面引用成员方法,可以通过 对象 :: 成员方法
进行引用,且通过实例化类的对象,可以引用类中的任何一个成员方法,当然前提是这个方法能满足引用方法的要求。
而引用类的成员方法,和上面引用成员方法不一样,它以接口实现方法的第一个参数作为当前对象,并执行方法引用,如果接口实现方法中出现多个参数,那么第一个参数将作为调用引用方法的对象,从第二个参数开始,必须和引用方法的形参一样。
举例:
ArrayList<String> strs = new ArrayList<>();
Collections.addAll(strs, "aaa", "bbb", "ccc", "ddd");
// 需求:需要把集合中的所有字母变为大写
我们知道,String 类中,是没有静态方法,或接收参数的成员方法,对字母变为大写,
String 中只有一个方法,那就是成员方法 str.toUpperCase() 方法
toUpperCase 方法不接收参数,但会直接对实例对象 str 的字母改成大写
我们使用上面的引用成员方法的方式,会报错
// 通过 new String() 实例化再进行引用会报错
strs.stream().map(new String()::toUpperCase);
这是因为,map() 方法的实现接口方法中,需要传递一个参数 String s:
public String apply(String s) {
return null;
}
而 toUpperCase() 方法中,不需要接收参数,这使得规则不成立!
引用类的成员方法
语法:
类 :: 成员方法
通过引用类的成员方法,使实现接口方法中接收的参数,作为实例对象
strs.stream().map(String::toUpperCase);
规则:
1.实现接口方法中所传递的第一个参数,作为实例对象,且局限第一个参数的类型的成员方法
也就是说,如果接口方法中所传递的第一个参数是 String 类型,那么只能调用 String 类型中的成员方法
且,所传递的第一个参数 s 将被作为String 的对象看待。
2.如果实现接口方法中传递了多个参数,则从第二个参数开始,它的参数类型和参数个数,都要对应类的成员方法中的参数类型和个数一致
也就是说,假如 public String apply(String s1, String s2, String s3) ,实现方法中出现3个参数,那么
s1 将被作为实例对象,且限制了只能调用 s1 的类型 => String 类的成员方法 , 最后可以看作 => s1.toUpperCase()
被引用的方法中,就需要接收两个参数,且参数类型必须一致 => public String toUpperCase(String s1, String s2)
最后就相当于 s1.toUpperCase(s2, s3)
引用构造方法
语法:类名 :: new
strNum.stream().map(numMin :: new);
// 需求,把Stream流 中的每个成员,打包成一个 NumberMin 对象
class NumberMin {
private int number;
// 在构造函数中,定义一个和接口实现方法一样的形参
// 在引用构造函数中,如果是要打包成一个类实例
// 则在构造函数中,不需要考虑返回问题
// numMin :: new 引用相当于 new numMin() ,此时,已经存在实例对象
public NumberMin(String s){
this.number = Integer.parseInt(s);
}
}
引用数组构造方法
语法:数组类型[] :: new
示例:Integer[] :: new
相当于 new Integer[]{} 或者 new Integer[n];
通过引用数组构造方法,可以创建一个数组
示例:
ArrayList<Integer> ints2 = new ArrayList<>();
Collections.addAll(ints2, 3, 21, 6, 2, 54, 6);
// 需求,把集合中的集合成员,放到一个数组中???
我们可以通过 toArray() 方法,指定一个数组类型,并返回我们指的类型的数组
ints2.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[0];
}
});
其实我们还能通过引用数组的构造方法
ints2.stream().toArray(Integer[]::new);
Integer[] 的构造函数中,有一个接收了 value 的构造函数,相当于 apply() 方法返回了 new Integer[value];
注意:引用数组构造函数的前提是,Stream流中的数据类型,必须和 引用数组 的类型一致
也就是说,List 中的成员类型是 Integer,才可以引用 Integer[]::new 方法,不能引用别的数组类型。
P.S:在底层中,Java对数组的创建有其描述,因此创建数组其实也有构造函数。
共有 0 条评论