I'm struggling to see why the following code compiles:
public class MethodRefs {
public static void main(String[] args) {
Function<MethodRefs, String> f;
f = MethodRefs::getValueStatic;
f = MethodRefs::getValue;
}
public static String getValueStatic(MethodRefs smt) {
return smt.getValue();
}
public String getValue() {
return "4";
}
}
I can see why the first assignment is valid - getValueStatic obviously matches the specified Function type (it accepts a MethodRefs object and returns a String), but the second one baffles me - the getValue method accepts no arguments, so why is it still valid to assign it to f?
-
1Possible duplicate of lambda with non-static methods in Java 8Didier L– Didier L2017年04月25日 20:16:58 +00:00Commented Apr 25, 2017 at 20:16
-
1Also :: (double colon) operator in Java 8 and Use of double colons - difference between static and non-static method referencesDidier L– Didier L2017年04月25日 20:20:23 +00:00Commented Apr 25, 2017 at 20:20
5 Answers 5
The second one
f = MethodRefs::getValue;
is the same as
f = (MethodRefs m) -> m.getValue();
For non-static methods there is always an implicit argument which is represented as this in the callee.
NOTE: The implementation is slightly different at the byte code level but it does the same thing.
3 Comments
public String getValue(MethodRefs this) is legal and identical to public String getValue().Lets flesh it out a bit:
import java.util.function.Function;
public class MethodRefs {
public static void main(String[] args) {
Function<MethodRefs, String> f;
final MethodRefs ref = new MethodRefs();
f = MethodRefs::getValueStatic;
f.apply(ref);
//is equivalent to
MethodRefs.getValueStatic(ref);
f = MethodRefs::getValue;
f.apply(ref);
//is now equivalent to
ref.getValue();
}
public static String getValueStatic(MethodRefs smt) {
return smt.getValue();
}
public String getValue() {
return "4";
}
}
Comments
A non-static method essentially takes its this reference as a special kind of argument. Normally that argument is written in a special way (before the method name, instead of within the parentheses after it), but the concept is the same. The getValue method takes a MethodRefs object (its this) and returns a string, so it's compatible with the Function<MethodRefs, String> interface.
Comments
In the Java Tutorial it is explained that there are 4 different types of method references:
- reference to a static method
- reference to an instance method of a particular object
- reference to an instance method of an arbitrary object of a particular type
- reference to a constructor
Your case is #3, meaning that when you have an instance of MethodRef i.e. ref, calling apply on your function f will be equivalent to String s = ref.getValue().
Comments
For non-static methods, the type of this is considered implicitly to be the first argument type. Since it's of type MethodRefs, the types check out.