• 技术文章 >Java >java教程

    深入解析Java中的方法引用

    长期闲置长期闲置2022-06-14 19:11:34转载335
    本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于方法引用的相关问题,方法大家都知道,就是我们在编写代码的时候定义的方法。而方法引用就是用什么东西来引用这个方法。而引用方法说白了它的目的就是对Lambda表达式的一个进一步优化,从而减少代码的一个更简单的编写,希望对大家有帮助。

    推荐学习:《java视频教程

    什么是方法引用?

    其实我们就从字面就开始理解,方法大家都知道,就是我们在编写代码的时候定义的方法。而方法引用就是用什么东西来引用这个方法。而引用方法说白了它的目的就是对Lambda表达式的一个进一步优化,从而减少代码的一个更简单的编写。对!你没有听错,Lambda表达式已经很优化了,那还要怎么优化呢?当我们的代码中出现了对应的类、对象、super、this的时候我们就可以使用方法引用,而这个方法引用的前提就是我们有Lambda表达式。那它是怎么样来用的呢?我们就接着往下看吧。

    方法引用符

    既然标题是方法引用符,什么是方法引用符呢?方法引用符就是双冒号【::】,这就是方法引用,而这也是一种新语法,是一种引用运算符,方法引用就是通过它来实现的。如果Lambda要表达的函数方案已经存在于某个方法的实现中,我们就可以通过双冒号来引用该方法实现对Lambda的代替。

    注意:Lambda中传递的参数一定是方法引用中那个方法可接受的类型,否则会抛出异常。

    如何使用方法引用?

    方法引用可以通过以下几方面来使用:

    4ecab04263844e9b97ff81cc585dc820.jpeg

    既然是有以上几种方式的方法引用,那我们接下来就逐一进行学习一下吧。

    通过对象名引用成员方法

    那怎样来通过对象名引用方法呢?我们知道对象是通过类来创建的,所以我们首先要创建一个类,然后再类中定义一个成员方法,再通过类创建一个对象,用对去引用这个成员方法。

    例如:

    定义一个成员方法,传递字符串,把字符串按照大写输出

    我们把上面的需求来实现一下吧。

    先定义一个类

    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中的方法引用的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:CSDN,如有侵犯,请联系admin@php.cn删除
    专题推荐:java
    上一篇:实例详解Java基础的控制语句 下一篇:完全掌握Java锁(图文解析)
    20期PHP线上班

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• 怎么理解Java中的lambda表达式• JAVA外观模式详解• Java图文详解之实现图书管理系统• JavaScript隐藏机制之垃圾回收知识总结• Java集合框架之PriorityQueue优先级队列
    1/1

    PHP中文网