How to Get a Reference to a Method

Get Method reference from Method object

You just need to use Method.invoke. Here is an example:

public class SomeObject{

public String someMethod(){
return "Test";
}
}

public String expectsMethodRef( Function<SomeObject, String> f ){
SomeObject so = new SomeObject();
return f.apply(so);
}

And here is how you invoke using plain lambda and Method object.

    //plain lmbda
expectsMethodRef( SomeObject::someMethod );

//with method object
Method someMethod = SomeObject.class.getMethod("someMethod");
expectsMethodRef( (so) -> {
try {
return (String)someMethod.invoke(so);
} catch (Exception e) {
return null;
}
} );

How to get Method Reference for all methods in a class (Java)?

There is no solution that works without Reflection as the dynamic discovery of existing methods is a reflective operation. However, once methods are discovered and a method reference instance (or the dynamic equivalent of it) has been created, the actual invocation of the code runs without Reflection:

class Test {
public static double op0(double a) { ... }
public static double op1(double a) { ... }
public static double op2(double a) { ... }
public static double op3(double a) { ... }
public static double op4(double a) { ... }

static final Map<String, DoubleUnaryOperator> OPS;
static {
HashMap<String, DoubleUnaryOperator> map=new HashMap<>();
MethodType type=MethodType.methodType(double.class, double.class);
MethodType inT=MethodType.methodType(DoubleUnaryOperator.class);
MethodHandles.Lookup l=MethodHandles.lookup();
for(Method m:Test.class.getDeclaredMethods()) try {
if(!Modifier.isStatic(m.getModifiers())) continue;
MethodHandle mh=l.unreflect(m);
if(!mh.type().equals(type)) continue;
map.put(m.getName(), (DoubleUnaryOperator)LambdaMetafactory.metafactory(
l, "applyAsDouble", inT, type, mh, type).getTarget().invokeExact());
} catch(Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
OPS=Collections.unmodifiableMap(map);
}
}

Once the class has been initialized, you can invoke a particular op without Reflection using OPS.get(name).applyAsDouble(doubleValue) or invoke all ops using, e.g.

OPS.forEach((name,op)-> System.out.println(name+'('+42+") => "+op.applyAsDouble(42)));

How can I get a reference to a method?

You want Object#method:

---------------------------------------------------------- Object#method
obj.method(sym) => method
------------------------------------------------------------------------
Looks up the named method as a receiver in obj, returning a Method
object (or raising NameError). The Method object acts as a closure
in obj's object instance, so instance variables and the value of
self remain available.

class Demo
def initialize(n)
@iv = n
end
def hello()
"Hello, @iv = #{@iv}"
end
end

k = Demo.new(99)
m = k.method(:hello)
m.call #=> "Hello, @iv = 99"

l = Demo.new('Fred')
m = l.method("hello")
m.call #=> "Hello, @iv = Fred"

Now your code becomes:

private
def setup_map
@map = {
'a' => method(:a),
'b' => method(:b),
'c' => method(:c)
}
# or, more succinctly
# @map = Hash.new { |_map,name| _map[name] = method(name.to_sym) }
end

public
def call(arg)
@map["a"][arg] if arg > 10
@map["b"][arg] if arg > 20
@map["c"][arg] if arg > 30
end

Java 8 method reference: how to determine which method to take?

NameCreator::createName implies that either the method is static (kind #1 in the table below), or that the functional interface target also takes an instance of the class (kind #3, for example
BiFunction<NameCreator, String, String>). Your methods are not static, and so presumably your target does not take an instance, which is why you get the "Cannot resolve method" error. You probably want to use the method reference on an instance (kind #2). From within the class, you can use:

Function<String, String> func = this::createName

From outside the class you can use:

NameCreator creator = new NameCreator();
Function<String, String> func = creator::createName;

As to whether the one- or two-parameter version is used, it depends on what functional interface is being targeted. The above will use your first method, because Function<String, String> takes a String and returns a String. The following functional interface, as an example, would use your second method:

NameCreator creator = new NameCreator();
BiFunction<String, String, String> func = creator::createName;

See: Function, BiFunction, and the whole java.util.function package

You may also be interested in the Java tutorial on method references, specifically this part:


There are four kinds of method references:

Kind                                                   | Example
==============================================================================================
Reference to a static method | ContainingClass::staticMethodName
-------------------------------------------------------+--------------------------------------
Reference to an instance method of a particular object | containingObject::instanceMethodName
-------------------------------------------------------+--------------------------------------
Reference to an instance method of an arbitrary object | ContainingType::methodName
of a particular type |
-------------------------------------------------------+--------------------------------------
Reference to a constructor | ClassName::new
==============================================================================================

get reference to methods object, when method called from other class (javascript)

Updated fiddle, using apply method (same can be achieved using call, jQuery.proxy, bind) to maintain correct scope:

var callObject = {

call: function(func) {
// Needs scope object as first parameter.
func.apply(object, [3]);
}
}

This way, by using any of these methods, we are able to specify what scope our function should resolve to.

Here is a great article giving more details on this aspect.

How to get the MethodInfo of a Java 8 method reference?

No, there is no reliable, supported way to do this. You assign a method reference to an instance of a functional interface, but that instance is cooked up by LambdaMetaFactory, and there is no way to drill into it to find the method you originally bound to.

Lambdas and method references in Java work quite differently than delegates in C#. For some interesting background, read up on invokedynamic.

Other answers and comments here show that it may currently be possible to retrieve the bound method with some additional work, but make sure you understand the caveats.

How can I get a method reference for an instance method with a dynamically bound target

Via Reflection, you can get an equivalent behavior to that one described in Java 8. You can create an instance of a Delegate with a null target and dynamically binding its first argument to the this method parameter. For your example you can create the toStr delegate in the following way:

MethodInfo methodToStr = typeof(object).GetMethod("ToString");
Func<Object, String> toStr = (Func<Object, String>) Delegate.CreateDelegate(
typeof(Func<Object, String>),
methodToStr);

Is it possible to get a reference to a Java method to invoke it later?

Yes, it is possible.

You just have the get the method and invoke it.

Here's some sample code:

$cat InvokeMethod.java  
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class InvokeMethod {

public static void invokeMethod( Method m , Object o , Object ... args )
throws IllegalAccessException,
InvocationTargetException {

m.invoke( o, args );

}

public static void main( String [] args )
throws NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {

SomeObject object = new SomeObject();
Method method = object.getClass().getDeclaredMethod( "someMethod", String.class );
invokeMethod( method, object, "World");

}
}

class SomeObject {
public void someMethod( String name ){
System.out.println( " Hello " + name );
}
}
$javac InvokeMethod.java
$java InvokeMethod
Hello World
$

Now the question is, what are you trying to do? perhaps are better ways. But as for your question the answer is YES.



Related Topics



Leave a reply



Submit