JAVA8学习——深入浅出方法引用(学习过程)

方法引用:method reference

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

Copy
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类如下

Copy
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. 类名::方法名.#

  • 具体实现:
Copy
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. 引用名(对象)::实例方法名#

和第一种方法类似

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

具体实现:

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

3.类名::实例方法名#

Copy
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 等几个参数都是如此。

Copy
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对象。

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

默认方法#

用案例再次解释默认方法

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

posted @   dawa大娃bigbaby  阅读(260)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示
CONTENTS