關於java8的方法引用
關於java8的方法引用
今天偶然看到一段程式碼
//首先有一個Studeng類 有一個靜態方法,有個例項方法
class Student{
class Student {
private String name;
public Student(){
}
public Student(String name){
this.name = name;
}
//例項方法 say()
public void say() {
System.out.println(name);
}
//靜態方法 say2()
public static void say2(String name) {
System.out.println(name);
}
}
注意:lists2.forEach(Student::say);
Student是類名, say() 是例項方法;
這裡就是我的疑問,為什麼可以呼叫例項方法呢?不應該通過物件呼叫嗎??
List<Student> lists2 = Arrays.asList(newStudent("張三"),new Student("李四"));
lists2.forEach(Student: :say);
//注意 這裡Student是類名,呼叫的是例項方法say(),這裡就是我的疑問,為什麼可以呼叫例項方法呢?不應該通過物件呼叫嗎??
lists2.forEach(Student::say); 為啥這裡可以呼叫類的例項方法呢?
於是乎,我又寫了一個例子,我把List的泛型裡面的型別改成:String,
結果:發現如果在呼叫say()例項方法就會編譯器報錯;
這裡就必須呼叫靜態方法say2()靜態方法才行!
那就奇了怪了,為啥一個可以呼叫,一個編譯報錯
改成靜態方法就可以了
List<String> lists = new ArrayList<>( );
lists.forEach(Student::say2);
//這裡就必須呼叫靜態方法了,否則的話編譯器會報錯!如下圖
那這是為什麼呢?上面的為什麼可以通過類呼叫例項方法呢?
我們都知道 :類是優先於例項存在的,我們new()一個物件,必須要先載入類!
大家可以看到這兩個方法唯一的區別就是list 裡面的型別
一個是Student類,一個是String 類,型別不同
所以我就去看了java8的文件,終於解決我的疑問了;
以下摘自java8文件:
引用與Java8文件內容:
如何構建方法引用方法引用主要有三類。
(1) 指向靜態方法的方法引用(例如Integer的parseInt方法,寫作Integer::parseInt)。
(2) 指向任意型別例項方法的方法引用(例如String的length方法,寫作String::length)。
(3) 指向現有物件的例項方法的方法引用(假設你有一個區域性變數expensiveTransaction用於存放Transaction型別的物件,它支援例項方法getValue,那麼你就可以寫expensiveTransaction::getValue)。第二種和第三種方法引用可能乍看起來有點兒暈。類似於String::length的第二種方法引用的思想就是你在引用一個物件的方法,而這個物件本身是Lambda的一個引數。例如,Lambda表示式(String s) -> s.toUppeCase()可以寫作String::toUpperCase。但第三種方法引用指的是,你在Lambda中呼叫一個已經存在的外部物件中的方法。
分析:
(1):指向靜態方法的方法引用:就是 類名::靜態方法
List<String> lists = new ArrayList<>();
lists.forEach(Student::say2);
//類名:Student::靜態方法:say2,這個很好了解
(3) :指向現有物件的例項方法的方法引用:就是 物件::例項方法
List<String> lists = new ArrayList<>();
Student stu = new Student();
lists.forEach(stu::initMethod);
//已存在的外部物件:student的例項方法:initMethod
//這個也很好理解,就是呼叫物件的方法 物件::例項方法
上面兩個都是很好理解的,跟我們理解的一樣,類呼叫靜態方法,物件呼叫例項方法,第二種就是上面遇到的情況
(2) :****☆指向任意型別例項方法的方法引用:
你在引用一個物件的方法,而這個物件本身是Lambda的一個引數。例如,Lambda表示式(String s) -> s.toUppeCase()可以寫作String::toUpperCase。但第三種方法引用指的是,你在Lambda中呼叫一個已經存在的外部物件中的方法。
List<Student> lists2 = Arrays.asList(newStudent("張三"),new Student("李四"));
lists2.forEach(Student::say);
**//所以這裡我們就應該明白為什麼可以呼叫例項方法了,因為我們的Student物件是lambda的一個引數,所以才可以呼叫,**
補充一個例子,害怕大家沒有理解
List<String> lists = new ArrayList<>();
lists.forEach(String::length);
//String的length方法並不是靜態方法,為什麼可以呼叫,是因為String是lambda的一個引數,所以可以呼叫
String的length方法並不是一個靜態方法,為什麼可以類名:: zh這樣的形式呼叫,主要是 因為String是lambda的一個引數,所以可以呼叫
總結
因為我們的Student物件是lambda的一個引數,所以才可以呼叫例項方法,文件也解決了我的疑惑!歡迎大家一起交流