Java 8中String类非静态方法toUpperCase()的方法引用如何工作?
嘿,这个问题戳中了Java 8方法引用里很容易混淆的点!刚接触的时候我也纳闷:明明toUpperCase()是String的实例方法,得靠具体的String对象才能调用,为啥用String::toUpperCase这种类名开头的写法就能行?其实这是Java方法引用的一种特定类型,我给你拆解明白:
先搞懂「类名::实例方法」对应的函数式接口逻辑
方法引用本质是lambda表达式的语法糖,String::toUpperCase对应的lambda其实是(String s) -> s.toUpperCase()——你看,这里lambda接收一个String实例,然后调用它的toUpperCase()方法。
这种写法对应的是接收单个参数、返回结果的函数式接口,最典型的就是Function<String, String>:
// 方法引用和lambda完全等价 Function<String, String> upperConverter1 = String::toUpperCase; Function<String, String> upperConverter2 = s -> s.toUpperCase(); // 调用的时候,传入的参数就是要调用toUpperCase()的实例 String upper = upperConverter1.apply("hello world"); // 结果是"HELLO WORLD"
背后的绑定逻辑
当你用「类名::实例方法」这种形式时,Java编译器会自动做一件事:把函数式接口抽象方法的第一个参数,作为调用该实例方法的对象。
拿String::toUpperCase来说:
toUpperCase()本身是无参数的实例方法- 对应的函数式接口(比如Function)的抽象方法
apply(T t)接收一个String参数 - 编译器就会把这个参数t,绑定为调用
toUpperCase()的那个String实例,也就是t.toUpperCase()
如果是带参数的实例方法,逻辑也是一样的。比如String的concat(String str)方法,String::concat就对应BiFunction<String, String, String>,因为BiFunction的apply(T t, U u)会把第一个参数t作为调用concat的实例,第二个参数u作为concat的参数,等价于t.concat(u)。
实际场景的例子
最常见的就是在Stream操作里用这种方法引用,比如把列表里的所有字符串转成大写:
List<String> lowerWords = Arrays.asList("cat", "dog", "bird"); List<String> upperWords = lowerWords.stream() .map(String::toUpperCase) // 这里map需要Function<String, String>,刚好匹配 .collect(Collectors.toList());
这里流中的每个String元素,都会被当作toUpperCase()的调用者,完美适配方法引用的逻辑。
对比其他方法引用类型
为了不让你混淆,再简单区分下:
具体实例::实例方法:比如"test"::toUpperCase,对应的是无参数的函数式接口(比如Supplier),因为调用者已经固定了,不需要再传参数 类名::静态方法:比如Integer::parseInt,对应的是接收参数、返回结果的接口(比如Function<String, Integer>),因为静态方法本身就需要参数,和函数式接口的参数对应
内容的提问来源于stack exchange,提问作者code goku

