Why are interface method invocations slower than concrete invocations?

Solution 1:

There are many performance myths, and some were probably true several years ago, and some might still be true on VMs that don't have a JIT.

The Android documentation (remember that Android don't have a JVM, they have Dalvik VM) used to say that invoking a method on an interfaces was slower than invoking it on a class, so they were contributing to spreading the myth (it's also possible that it was slower on the Dalvik VM before they turned on the JIT). The documentation does now say:

Performance Myths

Previous versions of this document made various misleading claims. We address some of them here.

On devices without a JIT, it is true that invoking methods via a variable with an exact type rather than an interface is slightly more efficient. (So, for example, it was cheaper to invoke methods on a HashMap map than a Map map, even though in both cases the map was a HashMap.) It was not the case that this was 2x slower; the actual difference was more like 6% slower. Furthermore, the JIT makes the two effectively indistinguishable.

Source: Designing for performance on Android

The same thing is probably true for the JIT in the JVM, it would be very odd otherwise.

Solution 2:

If in doubt, measure it. My results showed no significant difference. When run, the following program produced:

7421714 (abstract)
5840702 (interface)

7621523 (abstract)
5929049 (interface)

But when I switched the places of the two loops:

7887080 (interface)
5573605 (abstract)

7986213 (interface)
5609046 (abstract)

It appears that abstract classes are slightly (~6%) faster, but that should not be noticeable; These are nanoseconds. 7887080 nanoseconds are ~7 milliseconds. That makes it a difference of 0.1 millis per 40k invocations (Java version: 1.6.20)

Here's the code:

public class ClassTest {

    public static void main(String[] args) {
        Random random = new Random();
        List<Foo> foos = new ArrayList<Foo>(40000);
        List<Bar> bars = new ArrayList<Bar>(40000);
        for (int i = 0; i < 40000; i++) {
            foos.add(random.nextBoolean() ? new Foo1Impl() : new Foo2Impl());
            bars.add(random.nextBoolean() ? new Bar1Impl() : new Bar2Impl());
        }

        long start = System.nanoTime();    

        for (Foo foo : foos) {
            foo.foo();
        }

        System.out.println(System.nanoTime() - start);


        start = System.nanoTime();

        for (Bar bar : bars) {
            bar.bar();
        }

        System.out.println(System.nanoTime() - start);    
    }

    abstract static class Foo {
        public abstract int foo();
    }

    static interface Bar {
        int bar();
    }

    static class Foo1Impl extends Foo {
        @Override
        public int foo() {
            int i = 10;
            i++;
            return i;
        }
    }
    static class Foo2Impl extends Foo {
        @Override
        public int foo() {
            int i = 10;
            i++;
            return i;
        }
    }

    static class Bar1Impl implements Bar {
        @Override
        public int bar() {
            int i = 10;
            i++;
            return i;
        }
    }
    static class Bar2Impl implements Bar {
        @Override
        public int bar() {
            int i = 10;
            i++;
            return i;
        }
    }
}