Reputation: 11
In all the articles, it is said that java is copy-by-value and the inner class cannot access and modify the instance variables of the outer class. But it can be done now, why? My jdk is 1.8.
public class InnerClass {
private int counts = 0;
public void test(int src) {
int in = 100;
new Thread(new Runnable() {
private int a() {
counts++;
counts = src;
counts = in;
System.out.println("in a..." + counts);
return counts;
}
@Override
public void run() {
int s = a();
counts = s;
System.out.println("in run, " + counts);
}
}).start();
}
public int getCounts() {
return this.counts;
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.test(99);
try {
Thread.sleep(1000);
} catch (java.lang.InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
System.out.println("in main," + innerClass.getCounts());
}
}
Upvotes: 0
Views: 82
Reputation: 51152
The articles you have read are about parameters and local variables in methods or constructors; not other kinds of variables, such as instance variables in your example. It is forbidden for an inner class to modify a parameter or local variable belonging to an enclosing method, but not for it to modify any other kind of variable.
The reason for this is that for a variable to remain accessible and modifiable by an object, the memory for that variable has to remain allocated for the lifetime of that object.
The enclosing instance of an inner class will remain in memory for the lifetime of the instance of the inner class, because the instance of the inner class maintains a reference to its enclosing instance, meaning the enclosing instance cannot be garbage-collected before the instance of the inner class. So it is safe for the inner class to read and write to that variable.
However, a parameter or a local variable is allocated on the stack, not on the heap; it is deallocated as soon as the method returns, which may be during the lifetime of the instance of the inner class. So it would be unsafe for the inner class to read or write to that variable after its memory has been deallocated and potentially allocated for a different variable.
This does raise the question of why the inner class is allowed to read (but not write to) a final or effectively-final parameter or local variable. The answer to this is that its value is copied to an automatically-generated field belonging to the inner class, and the inner class reads the value of that field. The field exists for the lifetime of the object, of course, because it is part of the object.
But that raises another question: why are only final or effectively-final variables copied to fields of the instance; why not allow mutable automatically-generated fields? The answer to that is that more than one instance of an inner class (perhaps more than one inner class) might try to access the same variable, and making copies for each instance would give unexpected behaviour, since changes made by one instance wouldn't be visible to another.
That could be solved by supporting proper closures, as languages like Javascript do, but it would require the Java compiler to synthesize a class to represent the closure of a method, which would add a lot of complexity to the language specification and the compiler. This complexity is unnecessary since you can always just use instance variables to achieve the same result.
Upvotes: 3
Reputation: 140613
Misconception on your end: such anonymous inner classes can not accept local variables of the enclosing scope. But they can access fields of the enclosing class without a problem.
Upvotes: 3