zoukankan      html  css  js  c++  java
  • JAVA8学习——深入浅出方法引用(学习过程)

    方法引用:method reference

    先简单的看一下哪里用到了方法引用:

    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表达式的一种语法糖

    我们可以将方法引用看做一个「函数指针」,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. 引用名(对象)::实例方法名

    和第一种方法类似

    定义一个实例:
    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());
        }
    }
    
    

    具体实现:

    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);
    

    默认方法

    用案例再次解释默认方法

    如果有两个接口,分别的默认方法签名都相同,都被一个类继承
    
    类里面需要使用 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()方法。

  • 相关阅读:
    数据库 的几种链接 join
    eclipse 无法记住svn密码
    loadrunner监控linux服务器
    谷歌浏览器跨域命令行方式失效
    努力学习的意义到底在哪里?(转载知呼上的答案)
    人的性欲为什么会被视为坏事?(转载)
    npm下载速度太慢
    使用systemback制作Ubuntu自定义系统镜像和系统备份(抄)
    使用bat脚本永久激活Windows系统(摘抄)
    fiddler软件测试——Fiddler抓取https设置详解(图文)(摘抄)
  • 原文地址:https://www.cnblogs.com/bigbaby/p/12150699.html
Copyright © 2011-2022 走看看