方法引用

方法引用
1、 方法引用提供一种引用而不执行方法的方式,这种特性与lambda表达式相关,因为它也需要兼容的函数式接口。
2、方法引用使用 JDK 8 新增的分割符“ :: ”。

一、静态方法的方法引用
一般语法: ClassName::methodName ,ClassName是静态方法methodName的类。
1、函数式接口
interface StringFunc{
String func(String str); //参数和返回类型都是String
}
2、StringUtils类,提供了一个静态方法,在这里 strReverse 是 func的一种实现。
class StringUtils{
public static String strReverse(String str){
String res ="";
for (int i = str.length()-1; i >= 0; i--) {
res += str.charAt(i);
}
return res;
}
}
3、使用函数式接口引用作为方法参数的类
此处,strMethods()方法没要求一定是static方法。
public class Lambda7 {
public static String strMethods( StringFunc sf, String in){
return sf.func(in); //调用函数式接口方法
}
}
4、方法引用
public static void main(String[] args) {
String instr = "this is a program";
String outstr = Lambda7.strMethods( StringUtils::strReverse , instr);
System.out.println(outstr);
}
此处,Lambda7.strMethods( StringUtils::strReverse, instr),将StringUtils类的静态方法strReverse的引用传递给了strMethods的第一个参数。因为strReverse和函数式接口的func方法兼容。因此 StringUtils::strReverse的结果是对象引用,strReverse提供了func()方法的具体实现。

二、实例方法的方法引用
1、一般语法: objName::methodName。 objName是对象名,methodName是objName对象的方法。
2、函数式接口
interface StringFunc{
String func(String str);
}
3、StringUtils类,提供了一个 普通方法 strReverse ,它是 func的一种实现。
class StringUtils{
public String strReverse(String str){
String res ="";
for (int i = str.length()-1; i >= 0; i--) {
res += str.charAt(i);
}
return res;
}
}
4、使用函数式接口引用作为方法参数的类
此处,strMethods()方法没要求一定是static方法。
public class Lambda7 {
public static String strMethods( StringFunc sf, String in){
return sf.func(in); //调用函数式接口方法
}
}
5、普通方法的方法引用。
public static void main(String[] args) {
String instr = "this is a program";
StringUtils utils = new StringUtils(); //先实例化类
String outstr = Lambda7.strMethods( utils::strReverse, instr);
System.out.println(outstr);
}

三、针对某个类所有对象公用的方法引用
1、一般语法: ClassName::methodName , methodName是类ClassName的普通方法。
2、该方式写出来的程序可读性差。

四、泛型中的方法引用
1、在泛型类或者泛型方法中,也可以使用方法引用。
(1)泛型函数式接口
interface MyFunc<T>{
int func(T[] vals, T v);
}
(2)与函数式接口兼容的具体方法,方法是泛型的,但包含方法的类不是泛型的。
class ArrayUtils{
public static <T> int match(T[] vals, T v){
int count = 0;
for (int i = 0; i < vals.length; i++) {
if(vals[i] == v)
count++;
}
return count;
}
}
(3)真正调用函数式接口的方法 myOp
static <T> int myOp(MyFunc<T> mf, T[] vals, T v){
return mf.func(vals, v);
}
(4)方法引用,将ArrayUtils类的match方法作为函数式接口的func()方法的具体实现,传递该方法的引用给myOp方法。其中,参数传递发生在 :: 之后,泛型指定发生在 :: 之后,方法名之前。同样,可以不必显式指定泛型参数类型,因为编译器会自动推断出具体类型。
public static void main(String[] args) {
Integer[] arr = {1,2,3,4,4,5,5,5,9};
int count = myOp( ArrayUtils::<Integer>match, arr, 5);
// int count = myOp( ArrayUtils::match, arr, 5); 也可以
System.out.println(count);
}
2、 常与集合框架一起使用。JDK 8 之后集合类中很多方法都可以使用lambda表达式。
3、示例:找到集合中最大的元素,既不使用Comparable接口,也不实现Comparator接口。
(1)自定义类(以往对类进行比较,有两种做法:类实现Comparable接口;自定义比较器类)
class MyClass{
private int val;
MyClass(int val){
this.val = val;
}
int getVal(){
return this.val;
}
}
(2)定义静态方法(该方法是Comparator函数式接口的具体实现)
static int compareVal(MyClass a, MyClass b){
return a.getVal() - b.getVal();
}
(3)实现MyClass对象之间的比较
public static void main(String[] args) {
ArrayList<MyClass> arr = new ArrayList<>();
arr.add(new MyClass(1));
arr.add(new MyClass(2));
MyClass max = Collections.max(arr, Lambda8::compareVal);
System.out.println(max.getVal());
}
其中,Collections.max(Collection col, Comparator com)方法,第二个参数是函数式接口引用,故而可以使用方法引用。

五、构造方法的方法引用
1、一般语法: ClassName::new
2、如下示例,但是 基本没有人会使用如此复杂的程序来构造对象
public class Lambda9 {
public static void main(String[] args) {
MyFunc mf = ClassA::new;
ClassA ca = mf.func(100); //调用有参数的构造方法
System.out.println(ca.getVal());
}
}
interface MyFunc{
ClassA func(int n);
}
class ClassA{
private int val;
ClassA(){
this.val = 0;
}
ClassA(int val){
this.val = val;
}
int getVal(){
return this.val;
}
}
注意:想要调用无参数的构造方法,需要再写一个函数式接口,接口方法是无参数的。可见,使用方法引用构造对象非常繁琐。
3、更为实际的用法,创建对象工厂。
(1)自定义两个类,ClassA和ClassB,ClassA是一个泛型类;ClassB是一个普通类。
class ClassA<T>{
private T val;
ClassA(){
this.val = null;
}
ClassA(T val){
this.val = val;
}
T getVal(){
return this.val;
}
}
class ClassB{
private String val;
ClassB(){
this.val = null;
}
ClassB(String val){
this.val = val;
}
String getVal(){
return this.val;
}
}
(2)函数式接口,包含两个泛型R和T,R是返回类型,T是参数类型。
interface MyFunc<R,T>{
R func(T v);
}
(3)静态工厂方法(构造对象的工厂,以函数式接口引用为参数)
public static <R,T> R myClassFactory(MyFunc<R,T> mf, T v){
return mf.func(v);
}
(4)使用静态工厂方法创建ClassA和ClassB类的对象。ClassA是泛型类,所以构造对象时要显式声明具体类。
ClassA<Integer> ca = Lambda9.myClassFactory( ClassA<Integer>::new, 100);
System.out.println(ca.getVal());
ClassB cb = myClassFactory( ClassB::new, "name");
System.out.println(cb.getVal());
(5)总结, 只要类的构造方法与函数式接口的抽象方法兼容,如上静态工厂方法就可以创建任意类型的对象

六、为数组创建构造函数引用
1、语法: type[] :: new
2、函数式接口(使用泛型,可以创建任意类型的数组)
interface ArrayCreator<T>{
T func(int n); //参数 n 指定数组的长度
}
3、创建ClassB对象数组,泛型的具体类型是ClassB[ ]
ArrayCreator< ClassB[]> ac = ClassB[]::new;
ClassB[] arr = ac.func(2);
arr[0] = new ClassB("this");










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值