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

Multi tool use
What happens to variables/objects in inner classes of function objects?
I have a function multi2
which returns inner class Inner
as an Object
.
multi2
Inner
Object
What happens to a
- where is it saved and how can I access it?
a
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());
}
}
5 Answers
5
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.
a
C.Inner
The value of a
is passed to the compiled Inner
constructor via an extra parameter.
a
Inner
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.
C.Inner.hashCode
a
Inner.hashCode
The variable in the outer scope must be final
1. The synthetic variable must be final
2 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.)
final
final
Inner
Inner
a
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.
javap
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.
a
Inner
Inner
multi2
a
a
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.
class Inner
multi2(param)
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.
a
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.
a
Can I Access a?
No you cannot access a
from outside you static method, it is restricted with in your static method.
a
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;
}
}
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.
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
.
a
multi2
a
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Great, can you add an explanation about trying to access
a
variable, like @Clayton answer.– Dennis Vash
Jul 2 at 12:51