首頁  >  文章  >  Java  >  深入解析Java中的方法引用

深入解析Java中的方法引用

WBOY
WBOY轉載
2022-06-13 17:55:192353瀏覽

本篇文章為大家帶來了關於java的相關知識,其中主要介紹了關於方法引用的相關問題,方法大家都知道,就是我們在編寫程式碼的時候定義的方法。而方法引用就是用什麼東西來引用這個方法。而引用方法說白了它的目的就是對Lambda表達式的一個進一步優化,從而減少程式碼的一個更簡單的編寫,希望對大家有幫助。

深入解析Java中的方法引用

推薦學習:《java影片教學

什麼是方法引用?

        其實我們就從字面上開始理解,方法大家都知道,就是我們在寫程式碼的時候定義的方法。而方法引用就是用什麼東西來引用這個方法。而引用方法說白了它的目的就是對Lambda表達式的一個進一步優化,從而減少程式碼的一個更簡單的編寫。對!你沒有聽錯,Lambda表達式已經很優化了,那還要怎麼優化呢?當我們的程式碼中出現了對應的類別、物件、super、this的時候我們就可以使用方法引用,而這個方法引用的前提就是我們有Lambda表達式。那它是怎麼樣來用的呢?我們就接著往下看吧。

方法引用符

        既然標題是方法引用符,什麼是方法引用符呢?方法引用符就是雙冒號【::】,這就是方法引用,而這也是一種新語法,是一種引用運算子,方法引用就是透過它來實現的。如果Lambda要表達的函數方案已經存在於某個方法的實作中,我們就可以透過雙冒號來引用該方法實現對Lambda的取代。

注意:Lambda中傳遞的參數一定是方法參考中那個方法可接受的型別,否則會拋出例外。

如何使用方法參考?

方法引用可以透過以下幾個面向來使用:

深入解析Java中的方法引用

 既然有以上幾種方式的方法引用,那我們接下來就逐一學習一下吧。

透過物件名稱來引用成員方法

        那如何透過物件名稱來引用呢?我們知道對像是透過類別來創建的,所以我們首先要創建一個類,然後再類中定義一個成員方法,再透過類創建一個對象,用對去引用這個成員方法。

例如:

定義一個成員方法,傳遞字串,把字串依照大寫輸出

我們把上面的需求來實現一下吧。

先定義一個類別

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.net。如有侵權,請聯絡admin@php.cn刪除