0

I'm confused with method references. Consider the following script.

public class Main {

    static interface I {
        void m();
    }

    static class A implements I {
        @Override
        public void m() {
            System.out.println("A");
        }
    }

    static class B implements I {
        @Override
        public void m() {
            System.out.println("B");
        }
    }

    public static void main(String[] args) {
        A a = new A(); B b = new B();
        I i; Runnable r;
        i = a;
        r = i::m;  // static reference? might infere class
        r.run(); // prints "A"
        run(i); // also prints "A"
        i = b;
        r.run(); // prints "A" instead of "B"!
        run(i); // prints "B"
        r = i::m;
        r.run(); // now prints "B"
        run(i); // also prints "B"
    }

    public static void run(I i) {
        Runnable r = i::m; // dynamic reference, cannot infere class
        r.run();
    }
}

So it seems that:

  • The compiler cannot inline method references because they are polymorphic. They are not resolved at compilation time, but at runtime.
  • But i::m does not behave like i.m()...

So my questions are:

Are method references using reflection? And why they do only once?

leppie
  • 115,091
  • 17
  • 196
  • 297

1 Answers1

2

If you think about how this code would be written without method references, but with classes and objects, it all makes sense:

r = i::m;

is basically equivalent to

private class IRunnable implements Runnable {
    private I i;

    public IRunnable(I i) {
        this.i = i;
    }

    @Override
    public void run() {
        i.m();
    }
}

Runnable r = new IRunnable(i);

So, if you assign another value to i after the IRunnable has been constructed, the IRunnable continues referencing the previous value, and calling its run() method again will still call the previous i's method.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Yes it makes sense. But you must agree that it is also confusing, because this feature is now the exception to Java's polymorphic nature. (They're polymorphic but only once). –  Mar 14 '15 at 12:54
  • It's not the exception at all. Java always passes references by value, and method references are no exception. You're creating a Runnable from `i`, and the Runnable uses a copy of this reference. – JB Nizet Mar 14 '15 at 13:00