3

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());
    }
}
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118

5 Answers5

4

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2

You have defined the class Inner inside the function so the scope of the class will be restricted with in the method. And your function is static so it will be live as long as the class definition is loaded. You have override the hashCode function inside the InnerClass so every time you are calling the multi2(param) you are creating the hashCode for the instance of InnerClass and returning the instance of the InnerClass.

So as for you questions, please correct me if i am wrong.

What happens to a ? a is with in the scope of your static method, so it will be live as long as the class definition is loaded.

Who allocates a? scope of a is restricted inside the static method and static method does not require instance to access it but as for the static method/variable allocation, i think it depends on JVM.

Can I Access a? No you cannot access a from outside you static method, it is restricted with in your static method.

pramesh
  • 501
  • 3
  • 11
0

Since the "a" is a local parameter, you could use a different approach to read the "a" value:

public class C {

  public static Object multi2(final int a) {
    return new Inner(a);
  }

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

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

class Inner{
  public int valueA;

  public Inner(int a)
  {
    valueA = a;
  }

  public int getA() {
    return valueA;
  }

  public int hashCode() {
    return 2*valueA;
  }
}
Dsenese1
  • 1,106
  • 10
  • 18
0

I wanted to know what was actually happening, so I compiled your code and looked at the bytecode output.

Basically what happens is the compiler adds in a constructor to your class 'Inner'. It also adds a single parameter to that constructor which takes 'a'. If your multi2() method was NOT static then there would probably also be a parameter to take 'this' where 'this' is the instance of 'C' that multi2() is executing on. BUT since we're in static context, there is no 'this'.

The compiler adds a private final field to your class 'Inner' and sets that private field using the value passed via the constructor. The compiler also converts

    new Inner()

into

    new Inner(a)

Hashcode then accesses the private field containing the value for a.

If 'a' was an object instead of a primitive, then it would be the same way, but a reference would be passed through instead of an actual number value.

How do you access this variable? Well you access it with reflections, but there are many problems:

1) You don't know the name of the field made by the compiler, so you can only get the name by looking at the bytecode. Don't trust decompilers as they might change the name. You gotta look at the bytecode yourself to find out.

2) The compiler probably marks the field as final, which means even if you can get reflections to access the field for you, you won't be able to update it.

3) It is entirely up to the compiler to figure out field names. Field names could change between builds depending on the compiler and it's mood.

Clayton
  • 96
  • 3
-1

Inner is a so called local class. a is a parameter passed to the method multi2 and accessable within that scope. Outside of that method, you cannot access a.

Glains
  • 2,773
  • 3
  • 16
  • 30