1. 程式人生 > 其它 >關於java8的方法引用

關於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的一個引數,所以才可以呼叫例項方法,文件也解決了我的疑惑!歡迎大家一起交流