Java 8中非静态方法以类名形式调用方法引用的疑问
核心概念:两种非静态方法引用形式
非静态方法的方法引用分为两类,这是你困惑的关键:
- 绑定引用:
对象::实例方法,方法引用提前绑定到指定对象,调用时无需再传入对象参数(比如你代码里的es::eatOverloaded) - 未绑定引用:
类名::实例方法,方法的调用者(即隐含的this)会作为函数式接口抽象方法的第一个参数传入,这就是你看到的用类名调用非静态方法的场景
示例1:EatSomething::similarToEat 解析
先看代码里的Function<EatSomething, String>接口,它的抽象方法是String apply(EatSomething t)——接收一个EatSomething类型参数,返回String。
EatSomething的similarToEat()是实例方法,正常调用需要eatObj.similarToEat(),其中eatObj是方法的调用者(即this)。
当使用EatSomething::similarToEat时,相当于把Function的apply方法传入的参数,作为similarToEat的调用者,完全等价于lambda表达式(EatSomething eat)->eat.similarToEat()。
代码中process方法调用func.apply(es),本质就是执行es.similarToEat(),因此能正常返回结果。
对比ff3 = es::eatOverloaded:eatOverloaded的方法签名是String eatOverloaded(EatSomething es),这里es是绑定的对象,apply传入的参数会作为eatOverloaded的方法参数,执行es.eatOverloaded(传入的参数),和未绑定引用的逻辑完全不同。
示例2:String::toUpperCase 解析
自定义接口MyCustomFunction的抽象方法是String test(String abc)——接收一个String参数,返回String。
String的toUpperCase()是实例方法,正常调用是str.toUpperCase()。使用String::toUpperCase时,test方法传入的abc参数会直接作为toUpperCase的调用者,等价于lambda表达式(str)->str.toUpperCase()。
当processs方法调用obj.test("abc")时,实际执行的是"abc".toUpperCase(),最终返回"ABC"。
总结
类名::实例方法是未绑定方法引用的标准写法,核心逻辑是:
- 函数式接口抽象方法的第一个参数,会作为该实例方法的调用者(
this) - 抽象方法的后续参数(如果存在),会作为实例方法的调用参数
- 这种写法和对应的lambda表达式功能完全一致,只是语法更简洁
内容的提问来源于stack exchange,提问作者J. Doe

