JAVA8學習——深刻淺出方法引用(學習過程)

方法引用:method reference

先簡單的看一下哪裏用到了方法引用:app

public class MethodReferenceTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "hello world");

//        list.forEach(item -> System.out.println(item));

        list.forEach(System.out::println);
    }
}

方法引用其實是lambda表達式的一種語法糖ide

咱們能夠將方法引用看作一個「函數指針」,function pointer函數

方法引用共分爲4類:

下面會逐步介紹四種類型,而且用代碼實現:公用的Student類以下測試

package com.dawa.jdk8.methodreference;

public class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

//這兩個方法,只是測試時候使用。實際設計有問題
    public static int compareStudenyByScore(Student student, Student student2) {
        return student.getScore() - student2.getScore();
    }

    public static int compareStudenyByName(Student student, Student student2) {
        return student.getName().compareToIgnoreCase(student2.getName());
    }
    
    //這樣設計才比較合理。
    public int compareByScore(Student student) {
        return this.score - student.getScore();
    }

    public int compareByName(Student student) {
        return this.name.compareToIgnoreCase(student.getName());
    }
    
}

1. 類名::方法名.

  • 具體實現:
public class MethodReferenceTest {
    public static void main(String[] args) {

        Student student1 = new Student("dawa", 20);
        Student student2 = new Student("erwa", 80);
        Student student3 = new Student("sanwa", 60);
        Student student4 = new Student("siwa", 40);

        List<Student> list = Arrays.asList(student1, student2, student3, student4);

//        list.sort((studentParam1, studentParam2) -> Student.compareStudenyByScore(studentParam1, studentParam2));
        list.sort(Student::compareStudenyByScore);
        list.forEach(item-> System.out.println(item.getScore()));

//        list.sort((studentParam1, studentParam2) -> Student.compareStudenyByName(studentParam1, studentParam2));
        list.sort(Student::compareStudenyByName);
        list.forEach(item-> System.out.println(item.getName()));

    }
}

2. 引用名(對象)::實例方法名

和第一種方法相似this

定義一個實例:
package com.dawa.jdk8.methodreference;

public class StudentComparator {

    public int compareStudentByScore(Student student1, Student student2) {
        return student1.getScore() - student2.getScore();
    }

    public int compareStudentByName(Student student1, Student student2) {
        return student1.getName().compareToIgnoreCase(student2.getName());
    }
}

具體實現:spa

StudentComparator studentComparator = new StudentComparator();
//list.sort((studentParam1,studentParam2) ->studentComparator.compareStudentByName(studentParam1,studentParam2));
list.sort(studentComparator::compareStudentByScore);
list.sort(studentComparator::compareStudentByName);

3.類名::實例方法名

list.sort(Student::compareByScore);
list.sort(Student::compareByName);
//方法是誰來調用的?
//必定是 sort方法裏面的lambda表達式的第一個參數來調用的compareByScore 實例方法 
//而lambda表達式的後續參數,都將做爲這個實例方法的參數

//擴展
List<String> cities = Arrays.asList("chengdu", "beijing", "shanghai", "chongqing");
//Collections.sort(cities,(value1,value2)->value1.compareToIgnoreCase(value2));
cities.sort(String::compareToIgnoreCase);
cities.forEach(System.out::println);
  • 額外知識點擴展:

System.out這個類中的out參數是null;賦值是經過最上面的函數registerNatives():底層是經過C來經過底層GNI實現的。 由於輸入輸出設備自己是跟硬件相關的。因此用經過底層的C來完成的。 Out,In,err 等幾個參數都是如此。設計

public final class System {

    /* register the natives via the static initializer.
     *
     * VM will invoke the initializeSystemClass method to complete
     * the initialization for this class separated from clinit.
     * Note that to use properties set by the VM, see the constraints
     * described in the initializeSystemClass method.
     */
    private static native void registerNatives();
    static {
        registerNatives();
    }
...

4. 構造方法引用:類名::new

實際上就夠調用了構造方法來生成一個new對象。指針

public String getStr(Supplier<String> supplier) {
        return supplier.get() + "test";
    }

    public String getString(String str, Function<String, String> function) {
        return function.apply(str);
    }
    
    //在main方法中調用
    MethodReferenceTest methodReferenceTest = new MethodReferenceTest();
    methodReferenceTest.getStr(String::new);
    methodReferenceTest.getString("hello", String::new);

默認方法

用案例再次解釋默認方法code

若是有兩個接口,分別的默認方法簽名都相同,都被一個類繼承

類裏面須要使用 Interface.super.method()來聲明你要使用哪一個方法。否則會編譯器報錯。

public interface MyInterface1 {
    default void mymethod1(){
        System.out.println("mymethod1");
    }
}

public interface MyInterface2 {
    default void mymethod1(){
        System.out.println("mymethod2");
    }
}

//以下
public class MyClass implements MyInterface1,MyInterface2 {
    @Override
    public void mymethod1() {
        MyInterface2.super.mymethod1();
    }
    
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.mymethod1();
    }
}

另外:若是一個類,繼承了接口1的實現類,又實現了接口2
那麼:默認調用實現類裏面的方法。這是沒有錯的
由於:JAVA認爲實現類更爲具體,接口只是類的契約。默認
因此:類中調用的是接口1中的方法

回顧

  • 方法引用的四種方式
  1. 類名::靜態方法名
  2. 引用名::實例方法名
  3. 類名::實例方法名(特殊)
  4. 構造方法:類名::new
  • 什麼狀況下會實現方法引用:
  1. lambda表達式只有一行方法
  2. 剛好這個方法和類中的方法對應

除此以外,方法引用是不能使用的。 方法引引用只是lambda的很具體的一種表達方式。對象

拋出一個問題:

JDK 爲何會有默認方法存在?是爲了規避什麼問題?

緣由: 版本升級,引入默認方法,就是爲了保證向後兼容。爲了防止版本升級在接口中添加方法,對之前開發的項目實現破壞性的影響。 如List接口中的sort()方法。

相關文章
相關標籤/搜索