Search code examples
javainner-classesfunction-object

What happens to variables/objects in inner classes of function objects?


I have a function multi2 which returns inner class Inner as an Object.

What happens to a - where is it saved and how can I access it?

public class C {
    private static Object multi2(final int a) {
        class Inner {
            public int hashCode() {
                return 2*a;
            }
        }
        return new Inner();     // What happens to a?
                                // Who allocates a?
                                // Can I Access a?
    }

    public static void main(String[] args) {
        Object o = multi2(6);
        System.out.println("o.hashCode() = " + o.hashCode());

        o = multi2(4);
        System.out.println("o.hashCode() = " + o.hashCode());
    }
}

Solution

  • What happens at the implementation level is that a copy of the value of a is saved in a synthetic instance variable declared in the compiled version of the C.Inner class.

    The value of a is passed to the compiled Inner constructor via an extra parameter.

    The C.Inner.hashCode method uses the value of the synthetic variable. Accessing a in the source code of Inner.hashCode is transformed into accessing the corresponding synthetic variable in the compiled code.

    The variable in the outer scope must be final1. The synthetic variable must be final2 in the Inner class. This maintains the illusion that (potentially) multiple instances of the Inner class are seeing the same a variable. (They aren't, but since the variable(s) can't be changed, it is not possible for the code of the inner class to tell the difference.)

    If you use javap to look at the bytecodes for the compiled example, you will see the mechanisms used to implement this in the outer and the inner classes.


    1 - or effectively final from Java 8 onwards.

    2 - If a could be mutated by an Inner method, then two Inner instances with the same outer class need to share a mutable variable whose lifetime is (now) longer than the stackframe for a multi2 call. That entails somehow turning a from stack variable into something that lives on the heap. It would be expensive and complicated.