Inner class and local variables - java

Why do I need to declare a local variable as final if my Inner class defined within the method needs to use it ?
Example :
class MyOuter2 {
private String x = "Outer2";
void doStuff() {
final String y = "Hello World";
final class MyInner {
String z = y;
public void seeOuter() {
System.out.println("Outer x is "+x);
System.out.println("Local variable is "+y);
MyInner mi = new MyInner();
mi.seeOuter();
}
}
}
}
Why the String y needs to be a final constant ? How does it impact ?

Local variables always live on the stack, the moment method is over all local variables are gone.
But your inner class objects might be on heap even after the method is over (Say an instance variable holds on to the reference), so in that case it cannot access your local variables since they are gone, unless you mark them as final

The answer is the two are in different scopes. So that variable could change before the inner class accesses it. Making it final prevents that.

It's because the inner class inside a function actually makes a copy of the local variable because local variable may be destroyed after the function call while the instance of the local class still exists. To make the two copies of the local variable always have the same value(to make them seem identical), you have to declare the variable as final.

I think this is to prevent that the programmer would make mistakes. This way, the compiler reminds the programmer that the variable will not be accessible anymore when you leave that method. This is critical with looping. Imagine this code:
public void doStuff()
{
InnerClass cls[] = new InnerClass[100];
for (int i = 0; i < 100; ++i)
{
cls[i] = new InnerClass()
{
void doIt()
{
System.out.println(i);
}
};
}
}
When the doIt() method is called, what will be printed? i changed while looping.
To prevent that confusion, you have to copy the variable to a local variable or create the variable final, but then you will be unable to loop.

Your inner class is final and so you shouldn't be able to modify anything from inside your final entity.

According to Java memory model use of final variable guarantees that the final variable are always initialized.
We get error when we try to use local variable without initialization.
using final guarantees the inner class that local variable which is been used is initialized.

Related

Why is it necessary to declare a field as final when to be used in an inner class? [duplicate]

a can only be final here. Why? How can I reassign a in onClick() method without keeping it as private member?
private void f(Button b, final int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
}
});
}
How can I return the 5 * a when it clicked? I mean,
private void f(Button b, final int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
return b; // but return type is void
}
});
}
As noted in comments, some of this becomes irrelevant in Java 8, where final can be implicit. Only an effectively final variable can be used in an anonymous inner class or lambda expression though.
It's basically due to the way Java manages closures.
When you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor. This avoids the compiler having to autogenerate various extra types to hold the logical state of the "local variables", as for example the C# compiler does... (When C# captures a variable in an anonymous function, it really captures the variable - the closure can update the variable in a way which is seen by the main body of the method, and vice versa.)
As the value has been copied into the instance of the anonymous inner class, it would look odd if the variable could be modified by the rest of the method - you could have code which appeared to be working with an out-of-date variable (because that's effectively what would be happening... you'd be working with a copy taken at a different time). Likewise if you could make changes within the anonymous inner class, developers might expect those changes to be visible within the body of the enclosing method.
Making the variable final removes all these possibilities - as the value can't be changed at all, you don't need to worry about whether such changes will be visible. The only ways to allow the method and the anonymous inner class see each other's changes is to use a mutable type of some description. This could be the enclosing class itself, an array, a mutable wrapper type... anything like that. Basically it's a bit like communicating between one method and another: changes made to the parameters of one method aren't seen by its caller, but changes made to the objects referred to by the parameters are seen.
If you're interested in a more detailed comparison between Java and C# closures, I have an article which goes into it further. I wanted to focus on the Java side in this answer :)
There is a trick that allows anonymous class to update data in the outer scope.
private void f(Button b, final int a) {
final int[] res = new int[1];
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
res[0] = a * 5;
}
});
// But at this point handler is most likely not executed yet!
// How should we now res[0] is ready?
}
However, this trick is not very good due to the synchronization issues. If handler is invoked later, you need to 1) synchronize access to res if handler was invoked from the different thread 2) need to have some sort of flag or indication that res was updated
This trick works OK, though, if anonymous class is invoked in the same thread immediately. Like:
// ...
final int[] res = new int[1];
Runnable r = new Runnable() { public void run() { res[0] = 123; } };
r.run();
System.out.println(res[0]);
// ...
An anonymous class is an inner class and the strict rule applies to inner classes (JLS 8.1.3):
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned before the body of the inner class.
I haven't found a reason or an explanation on the jls or jvms yet, but we do know, that the compiler creates a separate class file for each inner class and it has to make sure, that the methods declared on this class file (on byte code level) at least have access to the values of local variables.
(Jon has the complete answer - I keep this one undeleted because one might interested in the JLS rule)
You can create a class level variable to get returned value. I mean
class A {
int k = 0;
private void f(Button b, int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
k = a * 5;
}
});
}
now you can get value of K and use it where you want.
Answer of your why is :
A local inner class instance is tied to Main class and can access the final local variables of its containing method. When the instance uses a final local of its containing method, the variable retains the value it held at the time of the instance's creation, even if the variable has gone out of scope (this is effectively Java's crude, limited version of closures).
Because a local inner class is neither the member of a class or package, it is not declared with an access level. (Be clear, however, that its own members have access levels like in a normal class.)
To understand the rationale for this restriction, consider the following program:
public class Program {
interface Interface {
public void printInteger();
}
static Interface interfaceInstance = null;
static void initialize(int val) {
class Impl implements Interface {
#Override
public void printInteger() {
System.out.println(val);
}
}
interfaceInstance = new Impl();
}
public static void main(String[] args) {
initialize(12345);
interfaceInstance.printInteger();
}
}
The interfaceInstance remains in memory after the initialize method returns, but the parameter val does not. The JVM can’t access a local variable outside its scope, so Java makes the subsequent call to printInteger work by copying the value of val to an implicit field of the same name within interfaceInstance. The interfaceInstance is said to have captured the value of the local parameter. If the parameter weren’t final (or effectively final) its value could change, becoming out of sync with the captured value, potentially causing unintuitive behavior.
Well, in Java, a variable can be final not just as a parameter, but as a class-level field, like
public class Test
{
public final int a = 3;
or as a local variable, like
public static void main(String[] args)
{
final int a = 3;
If you want to access and modify a variable from an anonymous class, you might want to make the variable a class-level variable in the enclosing class.
public class Test
{
public int a;
public void doSomething()
{
Runnable runnable =
new Runnable()
{
public void run()
{
System.out.println(a);
a = a+1;
}
};
}
}
You can't have a variable as final and give it a new value. final means just that: the value is unchangeable and final.
And since it's final, Java can safely copy it to local anonymous classes. You're not getting some reference to the int (especially since you can't have references to primitives like int in Java, just references to Objects).
It just copies over the value of a into an implicit int called a in your anonymous class.
The reason why the access has been restricted only to the local final variables is that if all the local variables would be made accessible then they would first required to be copied to a separate section where inner classes can have access to them and maintaining multiple copies of mutable local variables may lead to inconsistent data. Whereas final variables are immutable and hence any number of copies to them will not have any impact on the consistency of data.
When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.
(http://en.wikipedia.org/wiki/Final_%28Java%29)
Methods within an anonomyous inner class may be invoked well after the thread that spawned it has terminated. In your example, the inner class will be invoked on the event dispatch thread and not in the same thread as that which created it. Hence, the scope of the variables will be different. So to protect such variable assignment scope issues you must declare them final.
private void f(Button b, final int a[]) {
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
a[0] = a[0] * 5;
}
});
}
As Jon has the implementation details answer an other possible answer would be that the JVM doesn't want to handle write in record that have ended his activation.
Consider the use case where your lambdas instead of being apply, is stored in some place and run later.
I remember that in Smalltalk you would get an illegal store raised when you do such modification.
Try this code,
Create Array List and put value inside that and return it :
private ArrayList f(Button b, final int a)
{
final ArrayList al = new ArrayList();
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
al.add(b);
}
});
return al;
}
Java anonymous class is very similar to Javascript closure, but Java implement that in different way. (check Andersen's answer)
So in order not to confuse the Java Developer with the strange behavior that might occur for those coming from Javascript background. I guess that's why they force us to use final, this is not the JVM limitation.
Let's look at the Javascript example below:
var add = (function () {
var counter = 0;
var func = function () {
console.log("counter now = " + counter);
counter += 1;
};
counter = 100; // line 1, this one need to be final in Java
return func;
})();
add(); // this will print out 100 in Javascript but 0 in Java
In Javascript, the counter value will be 100, because there is only one counter variable from the beginning to end.
But in Java, if there is no final, it will print out 0, because while the inner object is being created, the 0 value is copied to the inner class object's hidden properties. (there are two integer variable here, one in the local method, another one in inner class hidden properties)
So any changes after the inner object creation (like line 1), it will not affect the inner object. So it will make confusion between two different outcome and behaviour (between Java and Javascript).
I believe that's why, Java decide to force it to be final, so the data is 'consistent' from the beginning to end.
Java final variable inside an inner class[About]
inner class can use only
reference from outer class
final local variables from out of scope which are a reference type (e.g. Object...)
value(primitive) (e.g. int...) type can be wrapped by a final reference type. IntelliJ IDEA can help you covert it to one element array
When a non static nested (inner class) is generated by compiler - a new class - <OuterClass>$<InnerClass>.class is created and bounded parameters are passed into constructor[Local variable on stack] It is similar to closure[Swift about]
final variable is a variable which can not be reassign. final reference variable still can be changed by modifying a state
If it was be possible it would be weird because as a programmer you could make like this
//Not possible
private void foo() {
MyClass myClass = new MyClass(); //Case 1: myClass address is 1
int a = 5; //Case 2: a = 5
//just as an example
new Button().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
/*
myClass.something(); //<- what is the address - 1 or 2?
int b = a; //<- what is the value - 5 or 10 ?
//illusion that next changes are visible for Outer class
myClass = new MyClass();
a = 15;
*/
}
});
myClass = new MyClass(); //Case 1: myClass address is 2
int a = 10; //Case 2: a = 10
}
Maybe this trick gives u an idea
Boolean var= new anonymousClass(){
private String myVar; //String for example
#Overriden public Boolean method(int i){
//use myVar and i
}
public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);

Why instance initializers require *final* for outer variables in Java?

What semantics would the second example violate if it had access to the outer variable?
class A {
void f() {
int outer = 1;
// Access non-final outer variable through helper method
new A() {
int inner;
void init(int inner) {
this.inner = inner;
}
}.init(outer); // OK
// Access non-final outer variable through instance initializer
new A() {
{
// int inner = outer; // Does not compile
}
};
outer = 2;
}
}
It has nothing to do with instance initializers, but rather with the fact that you are capturing an outer local variable. If you captured the outer local variable in your helper method, it would equally not work:
new A() {
int inner;
void init() {
this.inner = outer;
}
}.init();
When you capture an outer local variable in a local or anonymous class, that outer local variable must be final (in Java 7 or before) or effectively final (in Java 8+). Your variable outer is not final, and (after your most recent edit) is not effectively final (which means it would still compile if it were declared as final), because you assign to it later.
Captured local variables are required to be final or effectively final due to the way Java implements capturing. In Java, when an object of a local or anonymous class is created, any local variables it captures are assigned (as if by =) into a separate independent copy inside the object (because the object may outlive the local scope where it was created). The variable state is not "shared" between the original local scope and the object(s) that capture it, even though they have the same name and only one variable was declared. Therefore, if you could assign to the variable, changes to one copy of the variable would not be reflected in the other copies, and it would be inconsistent. To prevent this, they prevent you from assigning to any version of the variable, by requiring that it be effectively final.

access to shadowed variable in local class

i'm new in java and i confused for below example
public class Test {
int testOne(){ //member method
int x=5;
class inTest // local class in member method
{
void inTestOne(int x){
System.out.print("x is "+x);
// System.out.print("this.x is "+this.x);
}
}
inTest ins=new inTest(); // create an instance of inTest local class (inner class)
ins.inTestOne(10);
return 0;
}
public static void main(String[] args) {
Test obj = new Test();
obj.testOne();
}
}
why i can't access to shadowed variable in inTestOne() method with "this" keyword in line 8
why i can't access to shadowed variable in inTestOne() method with "this" keyword in line 8
Because x is not a member variable of the class; it is a local variable. The keyword this can be used to access a member fields of the class, not local variables.
Once a variable is shadowed, you have no access to it. This is OK, because both the variable and the local inner class are yours to change; if you want to access the shadowed variable, all you need to do is renaming it (or renaming the variable that shadows it, whatever makes more sense to you).
Note: don't forget to mark the local variable final, otherwise you wouldn't be able to access it even when it is not shadowed.
this. is used to access members - a local variable is not a member, so it cannot be accessed this way when it's shadowed.

Difference between Static and final?

I'm always confused between static and final keywords in java.
How are they different ?
The static keyword can be used in 4 scenarios
static variables
static methods
static blocks of code
static nested class
Let's look at static variables and static methods first.
Static variable
It is a variable which belongs to the class and not to object (instance).
Static variables are initialized only once, at the start of the execution. These variables will be initialized first, before the initialization of any instance variables.
A single copy to be shared by all instances of the class.
A static variable can be accessed directly by the class name and doesn’t need any object.
Syntax: Class.variable
Static method
It is a method which belongs to the class and not to the object (instance).
A static method can access only static data. It can not access non-static data (instance variables) unless it has/creates an instance of the class.
A static method can call only other static methods and can not call a non-static method from it unless it has/creates an instance of the class.
A static method can be accessed directly by the class name and doesn’t need any object.
Syntax: Class.methodName()
A static method cannot refer to this or super keywords in anyway.
Static class
Java also has "static nested classes". A static nested class is just one which doesn't implicitly have a reference to an instance of the outer class.
Static nested classes can have instance methods and static methods.
There's no such thing as a top-level static class in Java.
Side note:
main method is static since it must be be accessible for an application to run before any instantiation takes place.
final keyword is used in several different contexts to define an entity which cannot later be changed.
A final class cannot be subclassed. This is done for reasons of security and efficiency. Accordingly, many of the Java standard library classes are final, for example java.lang.System and java.lang.String. All methods in a final class are implicitly final.
A final method can't be overridden by subclasses. This is used to prevent unexpected behavior from a subclass altering a method that may be crucial to the function or consistency of the class.
A final variable can only be initialized once, either via an initializer or an assignment statement. It does not need to be initialized at the point of declaration: this is called a blank final variable. A blank final instance variable of a class must be definitely assigned at the end of every constructor of the class in which it is declared; similarly, a blank final static variable must be definitely assigned in a static initializer of the class in which it is declared; otherwise, a compile-time error occurs in both cases.
Note: If the variable is a reference, this means that the variable cannot be re-bound to reference another object. But the object that it references is still mutable, if it was originally mutable.
When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. Once it has been assigned, the value of the final variable cannot change.
static means it belongs to the class not an instance, this means that there is only one copy of that variable/method shared between all instances of a particular Class.
public class MyClass {
public static int myVariable = 0;
}
//Now in some other code creating two instances of MyClass
//and altering the variable will affect all instances
MyClass instance1 = new MyClass();
MyClass instance2 = new MyClass();
MyClass.myVariable = 5; //This change is reflected in both instances
final is entirely unrelated, it is a way of defining a once only initialization. You can either initialize when defining the variable or within the constructor, nowhere else.
note A note on final methods and final classes, this is a way of explicitly stating that the method or class can not be overridden / extended respectively.
Extra Reading
So on the topic of static, we were talking about the other uses it may have, it is sometimes used in static blocks. When using static variables it is sometimes necessary to set these variables up before using the class, but unfortunately you do not get a constructor. This is where the static keyword comes in.
public class MyClass {
public static List<String> cars = new ArrayList<String>();
static {
cars.add("Ferrari");
cars.add("Scoda");
}
}
public class TestClass {
public static void main(String args[]) {
System.out.println(MyClass.cars.get(0)); //This will print Ferrari
}
}
You must not get this confused with instance initializer blocks which are called before the constructor per instance.
The two really aren't similar. static fields are fields that do not belong to any particular instance of a class.
class C {
public static int n = 42;
}
Here, the static field n isn't associated with any particular instance of C but with the entire class in general (which is why C.n can be used to access it). Can you still use an instance of C to access n? Yes - but it isn't considered particularly good practice.
final on the other hand indicates that a particular variable cannot change after it is initialized.
class C {
public final int n = 42;
}
Here, n cannot be re-assigned because it is final. One other difference is that any variable can be declared final, while not every variable can be declared static.
Also, classes can be declared final which indicates that they cannot be extended:
final class C {}
class B extends C {} // error!
Similarly, methods can be declared final to indicate that they cannot be overriden by an extending class:
class C {
public final void foo() {}
}
class B extends C {
public void foo() {} // error!
}
static means there is only one copy of the variable in memory shared by all instances of the class.
The final keyword just means the value can't be changed. Without final, any object can change the value of the variable.
final -
1)When we apply "final" keyword to a variable,the value of that variable remains constant.
(or)
Once we declare a variable as final.the value of that variable cannot be changed.
2)It is useful when a variable value does not change during the life time of a program
static -
1)when we apply "static" keyword to a variable ,it means it belongs to class.
2)When we apply "static" keyword to a method,it means the method can be accessed without creating any instance of the class
Think of an object like a Speaker. If Speaker is a class, It will have different variables such as volume, treble, bass, color etc. You define all these fields while defining the Speaker class. For example, you declared the color field with a static modifier, that means you're telling the compiler that there is exactly one copy of this variable in existence, regardless of how many times the class has been instantiated.
Declaring
static final String color = "Black";
will make sure that whenever this class is instantiated, the value of color field will be "Black" unless it is not changed.
public class Speaker {
static String color = "Black";
}
public class Sample {
public static void main(String args[]) {
System.out.println(Speaker.color); //will provide output as "Black"
Speaker.color = "white";
System.out.println(Speaker.color); //will provide output as "White"
}}
Note : Now once you change the color of the speaker as final this code wont execute, because final keyword makes sure that the value of the field never changes.
public class Speaker {
static final String color = "Black";
}
public class Sample {
public static void main(String args[]) {
System.out.println(Speaker.color); //should provide output as "Black"
Speaker.color = "white"; //Error because the value of color is fixed.
System.out.println(Speaker.color); //Code won't execute.
}}
You may copy/paste this code directly into your emulator and try.
Easy Difference,
Final : means that the Value of the variable is Final and it will not change anywhere. If you say that final x = 5 it means x can not be changed its value is final for everyone.
Static : means that it has only one object. lets suppose you have x = 5, in memory there is x = 5 and its present inside a class. if you create an object or instance of the class which means there a specific box that represents that class and its variables and methods. and if you create an other object or instance of that class it means there are two boxes of that same class which has different x inside them in the memory. and if you call both x in different positions and change their value then their value will be different. box 1 has x which has x =5 and box 2 has x = 6. but if you make the x static it means it can not be created again.
you can create object of class but that object will not have different x in them.
if x is static then box 1 and box 2 both will have the same x which has the value of 5. Yes i can change the value of static any where as its not final. so if i say box 1 has x and i change its value to x =5 and after that i make another box which is box2 and i change the value of box2 x to x=6. then as X is static both boxes has the same x. and both boxes will give the value of box as 6 because box2 overwrites the value of 5 to 6.
Both final and static are totally different. Final which is final can not be changed. static which will remain as one but can be changed.
"This is an example. remember static variable are always called by their class name. because they are only one for all of the objects of that class. so
Class A has x =5, i can call and change it by A.x=6; "
Static and final have some big differences:
Static variables or classes will always be available from (pretty much) anywhere. Final is just a keyword that means a variable cannot be changed. So if had:
public class Test{
public final int first = 10;
public static int second = 20;
public Test(){
second = second + 1
first = first + 1;
}
}
The program would run until it tried to change the "first" integer, which would cause an error. Outside of this class, you would only have access to the "first" variable if you had instantiated the class. This is in contrast to "second", which is available all the time.
Static is something that any object in a class can call, that inherently belongs to an object type.
A variable can be final for an entire class, and that simply means it cannot be changed anymore. It can only be set once, and trying to set it again will result in an error being thrown. It is useful for a number of reasons, perhaps you want to declare a constant, that can't be changed.
Some example code:
class someClass
{
public static int count=0;
public final String mName;
someClass(String name)
{
mname=name;
count=count+1;
}
public static void main(String args[])
{
someClass obj1=new someClass("obj1");
System.out.println("count="+count+" name="+obj1.mName);
someClass obj2=new someClass("obj2");
System.out.println("count="+count+" name="+obj2.mName);
}
}
Wikipedia contains the complete list of java keywords.
I won't try to give a complete answer here. My recommendation would be to focus on understanding what each one of them does and then it should be cleare to see that their effects are completely different and why sometimes they are used together.
static is for members of a class (attributes and methods) and it has to be understood in contrast to instance (non static) members. I'd recommend reading "Understanding Instance and Class Members" in The Java Tutorials. I can also be used in static blocks but I would not worry about it for a start.
final has different meanings according if its applied to variables, methods, classes or some other cases. Here I like Wikipedia explanations better.
Static variable values can get changed although one copy of the variable traverse through the application, whereas Final Variable values can be initialized once and cannot be changed throughout the application.

Why are only final variables accessible in anonymous class?

a can only be final here. Why? How can I reassign a in onClick() method without keeping it as private member?
private void f(Button b, final int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
}
});
}
How can I return the 5 * a when it clicked? I mean,
private void f(Button b, final int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
return b; // but return type is void
}
});
}
As noted in comments, some of this becomes irrelevant in Java 8, where final can be implicit. Only an effectively final variable can be used in an anonymous inner class or lambda expression though.
It's basically due to the way Java manages closures.
When you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor. This avoids the compiler having to autogenerate various extra types to hold the logical state of the "local variables", as for example the C# compiler does... (When C# captures a variable in an anonymous function, it really captures the variable - the closure can update the variable in a way which is seen by the main body of the method, and vice versa.)
As the value has been copied into the instance of the anonymous inner class, it would look odd if the variable could be modified by the rest of the method - you could have code which appeared to be working with an out-of-date variable (because that's effectively what would be happening... you'd be working with a copy taken at a different time). Likewise if you could make changes within the anonymous inner class, developers might expect those changes to be visible within the body of the enclosing method.
Making the variable final removes all these possibilities - as the value can't be changed at all, you don't need to worry about whether such changes will be visible. The only ways to allow the method and the anonymous inner class see each other's changes is to use a mutable type of some description. This could be the enclosing class itself, an array, a mutable wrapper type... anything like that. Basically it's a bit like communicating between one method and another: changes made to the parameters of one method aren't seen by its caller, but changes made to the objects referred to by the parameters are seen.
If you're interested in a more detailed comparison between Java and C# closures, I have an article which goes into it further. I wanted to focus on the Java side in this answer :)
There is a trick that allows anonymous class to update data in the outer scope.
private void f(Button b, final int a) {
final int[] res = new int[1];
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
res[0] = a * 5;
}
});
// But at this point handler is most likely not executed yet!
// How should we now res[0] is ready?
}
However, this trick is not very good due to the synchronization issues. If handler is invoked later, you need to 1) synchronize access to res if handler was invoked from the different thread 2) need to have some sort of flag or indication that res was updated
This trick works OK, though, if anonymous class is invoked in the same thread immediately. Like:
// ...
final int[] res = new int[1];
Runnable r = new Runnable() { public void run() { res[0] = 123; } };
r.run();
System.out.println(res[0]);
// ...
An anonymous class is an inner class and the strict rule applies to inner classes (JLS 8.1.3):
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned before the body of the inner class.
I haven't found a reason or an explanation on the jls or jvms yet, but we do know, that the compiler creates a separate class file for each inner class and it has to make sure, that the methods declared on this class file (on byte code level) at least have access to the values of local variables.
(Jon has the complete answer - I keep this one undeleted because one might interested in the JLS rule)
You can create a class level variable to get returned value. I mean
class A {
int k = 0;
private void f(Button b, int a){
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
k = a * 5;
}
});
}
now you can get value of K and use it where you want.
Answer of your why is :
A local inner class instance is tied to Main class and can access the final local variables of its containing method. When the instance uses a final local of its containing method, the variable retains the value it held at the time of the instance's creation, even if the variable has gone out of scope (this is effectively Java's crude, limited version of closures).
Because a local inner class is neither the member of a class or package, it is not declared with an access level. (Be clear, however, that its own members have access levels like in a normal class.)
To understand the rationale for this restriction, consider the following program:
public class Program {
interface Interface {
public void printInteger();
}
static Interface interfaceInstance = null;
static void initialize(int val) {
class Impl implements Interface {
#Override
public void printInteger() {
System.out.println(val);
}
}
interfaceInstance = new Impl();
}
public static void main(String[] args) {
initialize(12345);
interfaceInstance.printInteger();
}
}
The interfaceInstance remains in memory after the initialize method returns, but the parameter val does not. The JVM can’t access a local variable outside its scope, so Java makes the subsequent call to printInteger work by copying the value of val to an implicit field of the same name within interfaceInstance. The interfaceInstance is said to have captured the value of the local parameter. If the parameter weren’t final (or effectively final) its value could change, becoming out of sync with the captured value, potentially causing unintuitive behavior.
Well, in Java, a variable can be final not just as a parameter, but as a class-level field, like
public class Test
{
public final int a = 3;
or as a local variable, like
public static void main(String[] args)
{
final int a = 3;
If you want to access and modify a variable from an anonymous class, you might want to make the variable a class-level variable in the enclosing class.
public class Test
{
public int a;
public void doSomething()
{
Runnable runnable =
new Runnable()
{
public void run()
{
System.out.println(a);
a = a+1;
}
};
}
}
You can't have a variable as final and give it a new value. final means just that: the value is unchangeable and final.
And since it's final, Java can safely copy it to local anonymous classes. You're not getting some reference to the int (especially since you can't have references to primitives like int in Java, just references to Objects).
It just copies over the value of a into an implicit int called a in your anonymous class.
The reason why the access has been restricted only to the local final variables is that if all the local variables would be made accessible then they would first required to be copied to a separate section where inner classes can have access to them and maintaining multiple copies of mutable local variables may lead to inconsistent data. Whereas final variables are immutable and hence any number of copies to them will not have any impact on the consistency of data.
When an anonymous inner class is defined within the body of a method, all variables declared final in the scope of that method are accessible from within the inner class. For scalar values, once it has been assigned, the value of the final variable cannot change. For object values, the reference cannot change. This allows the Java compiler to "capture" the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed, the original variable is gone but the inner class's private copy persists in the class's own memory.
(http://en.wikipedia.org/wiki/Final_%28Java%29)
Methods within an anonomyous inner class may be invoked well after the thread that spawned it has terminated. In your example, the inner class will be invoked on the event dispatch thread and not in the same thread as that which created it. Hence, the scope of the variables will be different. So to protect such variable assignment scope issues you must declare them final.
private void f(Button b, final int a[]) {
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
a[0] = a[0] * 5;
}
});
}
As Jon has the implementation details answer an other possible answer would be that the JVM doesn't want to handle write in record that have ended his activation.
Consider the use case where your lambdas instead of being apply, is stored in some place and run later.
I remember that in Smalltalk you would get an illegal store raised when you do such modification.
Try this code,
Create Array List and put value inside that and return it :
private ArrayList f(Button b, final int a)
{
final ArrayList al = new ArrayList();
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int b = a*5;
al.add(b);
}
});
return al;
}
Java anonymous class is very similar to Javascript closure, but Java implement that in different way. (check Andersen's answer)
So in order not to confuse the Java Developer with the strange behavior that might occur for those coming from Javascript background. I guess that's why they force us to use final, this is not the JVM limitation.
Let's look at the Javascript example below:
var add = (function () {
var counter = 0;
var func = function () {
console.log("counter now = " + counter);
counter += 1;
};
counter = 100; // line 1, this one need to be final in Java
return func;
})();
add(); // this will print out 100 in Javascript but 0 in Java
In Javascript, the counter value will be 100, because there is only one counter variable from the beginning to end.
But in Java, if there is no final, it will print out 0, because while the inner object is being created, the 0 value is copied to the inner class object's hidden properties. (there are two integer variable here, one in the local method, another one in inner class hidden properties)
So any changes after the inner object creation (like line 1), it will not affect the inner object. So it will make confusion between two different outcome and behaviour (between Java and Javascript).
I believe that's why, Java decide to force it to be final, so the data is 'consistent' from the beginning to end.
Java final variable inside an inner class[About]
inner class can use only
reference from outer class
final local variables from out of scope which are a reference type (e.g. Object...)
value(primitive) (e.g. int...) type can be wrapped by a final reference type. IntelliJ IDEA can help you covert it to one element array
When a non static nested (inner class) is generated by compiler - a new class - <OuterClass>$<InnerClass>.class is created and bounded parameters are passed into constructor[Local variable on stack] It is similar to closure[Swift about]
final variable is a variable which can not be reassign. final reference variable still can be changed by modifying a state
If it was be possible it would be weird because as a programmer you could make like this
//Not possible
private void foo() {
MyClass myClass = new MyClass(); //Case 1: myClass address is 1
int a = 5; //Case 2: a = 5
//just as an example
new Button().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
/*
myClass.something(); //<- what is the address - 1 or 2?
int b = a; //<- what is the value - 5 or 10 ?
//illusion that next changes are visible for Outer class
myClass = new MyClass();
a = 15;
*/
}
});
myClass = new MyClass(); //Case 1: myClass address is 2
int a = 10; //Case 2: a = 10
}
Maybe this trick gives u an idea
Boolean var= new anonymousClass(){
private String myVar; //String for example
#Overriden public Boolean method(int i){
//use myVar and i
}
public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);

Categories

Resources