In java you use interfaces to pass methods to functions, this meaning you pass an object (while it is hidden by the language implementation) not a simple pointer (of course, you pass a reference to the object, which is some kind of pointer, but the class created on the fly to hold the call specific information is expressely hidden by the compiler to make the interface readable) This allows you to pass a method reference without having to first build a class implementing the interface required, but that is only notation, something is happening behind the scenes which is no as simple as the C way.
The reason for this is that, for static
methods, you only need to know the method pointer to the function, but for non static method, you need also to know the instance, so both references, are needed this time (the reference to the method to be called and the reference to the instance on which you want the method to be called) This makes Java compiler to encode differently the call to the static method than the call to the non-static one (despite they have the same interface) This allows you to pass also a lambda, that refers in its body to in-scope objects (that the compiler enforces to be final
due to the chances that the method is not known when it is going to be called, so the values should be constants at the time of the pass, to conserve their values at the time of the call)
When you specify e.g. myObject::toString
in a call to a function that requires a function without parameters to be passed as parameter, first Java prepares all things to allow a call to a function called toString
that requires an instance of MyClass
which is the class to which myObject
belongs, so you actually pass two references, one for the instance myObject
and the other to the method Object.toString()
if it has not been overriden in some subclass between Object
and MyClass
. And the class created on the fly, to define the pointer must have space to store the two pointers. In a different way, if you want to call a static String blabla()
method, you can do it (it has the same footprint as myObject::toString
, but will not require the instance) so when you pass MyClass::blabla
as parameter, the class created has no reference to designate the instance, as you are passing a static
method. This is all handled in a static way at compilation, but you link your C function at runtime, when it is loaded, and it will not have the appropiate interface to run any function pointer you can provide. The interface to C functions is stated by JNI, but you cannot impose Java how it has to define its functions to call them from C. The simple nature of pointer to function of C doesn't have a counterpart in Java.
This feature is also present in C++, for what is called a field reference or a method reference, and enforces the same preparation as Java does.
Anyway, in JNI there must be also ways by which you can callback a Java function/method from C. You should follow those guidelines, so you allow Java to prepare the interface adequately on each call, so you receive a properly initialized object. What you need to know is that the object will be an instance of an interface
(the one that must be implemented by the definition of the parameter type) and you should make a callback call to the interface method published by that interface. Cannot be simpler!!!! ;)