0
public interface Intf {
int size();
}

public class Cls1 implements Intf {
public int size() {
// implementation 1
}

public class Cls2 implements Intf {
public int size() {
// implementation 2
}

Now, which of the above two implementations will the following method reference refer to ?

Intf::size // note: using Intf

On what basis will the compiler choose between the above two? Or will this method reference throw an exception ?

  • Why do you think, the compiler would choose between the two classes `Cls1` or `Cls2` when you write `Intf::size`, which doesn’t refer to any of them? If you think the compiler chose an arbitrary implementation class, why not `Cls3`? – Holger Oct 12 '16 at 14:05

2 Answers2

0

The normal way that polymorphism works in general.

That is, the same way that if you have an intf1 someObject, you can call someObject.instanceMethodName() and it works.

This is no different for method references than any other kind of method invocation.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Please have another look at the final part of my question. I am assuming that 'instanceMethodName' exists in multiple classes that implement 'intf1'. So, having no class name mentioned in the method reference (only the intf1) , how can the compiler decide which class is the one? –  Oct 10 '16 at 06:43
  • You mean, `instanceMethodName` is not a method on the interface? If it is a method on the interface...then my answer still answers your question. This is exactly how polymorphism normally works. If it's not on the interface, then there's no way to do it not even with method references. – Louis Wasserman Oct 10 '16 at 06:44
  • Definitely it is on the interface, but as an abstract method. And it has different implementations in multiple classes. So, again, which class is the one? (in other words, if call using an object, then there is no problem. But we are calling using the interface). –  Oct 10 '16 at 06:51
  • No, there's still no problem calling it using the interface. You don't _need_ to know which class to reference, you just call it from the interface. – Louis Wasserman Oct 10 '16 at 06:51
  • If you have an object of an interface type, you can always call that method on the object. Period. There is zero difference here between method references and other method invocations. – Louis Wasserman Oct 10 '16 at 06:52
  • I know. But again, which version of implementation will the compiler choose? ... we have different implementations for that method in multiple classes. I hope you get my point. –  Oct 10 '16 at 06:55
  • `intf1::instanceMethodName` creates a lambda which accepts an object of type `intf1`. It will choose whichever implementation is tied to the actual runtime class of the object you pass into it. If you do `Function something = intf1::instanceMethodName`, and you do `something.apply(bar)`, it'll call `bar.instanceMethodName()`. Whatever the implementation of `bar.instanceMethodName()` is, is what it'll call. – Louis Wasserman Oct 10 '16 at 06:55
  • It's _not choosing an implementation._ The implementation is chosen when you _use_ the method reference and pass in an implementation of `intf1`. – Louis Wasserman Oct 10 '16 at 07:11
  • I have edited my question above, to better explain my point. Please have a look at it. –  Oct 10 '16 at 12:32
  • @basheer, it _does not choose between them._ `Intf::size` returns a functional interface type that accepts an `Intf` and returns an `int`. If you pass it an instance of `Cls1` it will call `Cls1.size()`. If you pass it an instance of `Cls2` it will call `Cls2.size()`. – Louis Wasserman Oct 10 '16 at 16:40
  • Here's an example run in real code. http://ideone.com/AcjUPa `Intf::size` _doesn't choose_, you choose when you _use_ the method reference. – Louis Wasserman Oct 10 '16 at 16:42
0

There will be no implementation selection in case you described (and it's a good thing, neither compiler nor interpreter can make that decision), because inferrable type of

Intf::size

is actually a

Function<? extends Intf, Integer>

or

ObjToIntFunction<? extends Intf> // considering that return type is primitive int

Which means that you create lambda that accepts a single instance assignable to Intf type and returns an integer number.

Now, if you say

new Cls1()::size

then you will produce an IntSupplier, or Supplier<Integer>, whichever's better suited. Suppliers being methods that accept no argument, require you to make implementation selection yourself.

M. Prokhorov
  • 3,894
  • 25
  • 39