本篇文章給大家帶來了關于java的相關知識,其中主要介紹了關于方法引用的相關問題,方法大家都知道,就是我們在編寫代碼的時候定義的方法。而方法引用就是用什么東西來引用這個方法。而引用方法說白了它的目的就是對Lambda表達式的一個進一步優化,從而減少代碼的一個更簡單的編寫,希望對大家有幫助。
推薦學習:《java視頻教程》
什么是方法引用?
其實我們就從字面就開始理解,方法大家都知道,就是我們在編寫代碼的時候定義的方法。而方法引用就是用什么東西來引用這個方法。而引用方法說白了它的目的就是對Lambda表達式的一個進一步優化,從而減少代碼的一個更簡單的編寫。對!你沒有聽錯,Lambda表達式已經很優化了,那還要怎么優化呢?當我們的代碼中出現了對應的類、對象、super、this的時候我們就可以使用方法引用,而這個方法引用的前提就是我們有Lambda表達式。那它是怎么樣來用的呢?我們就接著往下看吧。
方法引用符
既然標題是方法引用符,什么是方法引用符呢?方法引用符就是雙冒號【::】,這就是方法引用,而這也是一種新語法,是一種引用運算符,方法引用就是通過它來實現的。如果Lambda要表達的函數方案已經存在于某個方法的實現中,我們就可以通過雙冒號來引用該方法實現對Lambda的代替。
注意:Lambda中傳遞的參數一定是方法引用中那個方法可接受的類型,否則會拋出異常。
如何使用方法引用?
方法引用可以通過以下幾方面來使用:
既然是有以上幾種方式的方法引用,那我們接下來就逐一進行學習一下吧。
通過對象名引用成員方法
那怎樣來通過對象名引用方法呢?我們知道對象是通過類來創建的,所以我們首先要創建一個類,然后再類中定義一個成員方法,再通過類創建一個對象,用對去引用這個成員方法。
例如:
定義一個成員方法,傳遞字符串,把字符串按照大寫輸出
我們把上面的需求來實現一下吧。
先定義一個類
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視頻教程》