In the below code if i remove the keyword final from EditText i am an getting error in the line (6) where i pass EditText object (et) to the intent...I have to knw the significance of final keyword here...
final EditText et=(EditText)findViewById(R.id.t);
Button b=(Button)findViewById(R.id.b1);
b.setOnClickListener(new Button.OnClickListener(){
public void onClick(View v)<br>
{
Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText()));
startActivity(on);
}
});
It is because you use closure here. It means that inner class uses the context of the inbounded one. To use it the variables should be declared final in order not to be changed.
See more here.
Final essentially means that the variable et
will not be reassigned at any point and will remain around. This means that inner classes, like your listener, can trust that it wont be reassigned by some other thread which could cause all kinds of trouble.
final can also be used to modify a method or class definition, that would mean that the method can't be overriden by a subclass, or that the class cannot be extended.
Read this article to understand the implementation details involved:
The reason for this restriction
becomes apparent if we shed some light
on how local classes are implemented.
An anonymous local class can use local
variables because the compiler
automatically gives the class a
private instance field to hold a copy
of each local variable the class uses.
The compiler also adds hidden
parameters to each constructor to
initialize these automatically created
private fields. Thus, a local class
does not actually access local
variables, but merely its own private
copies of them. The only way this can
work correctly is if the local
variables are declared final, so that
they are guaranteed not to change.
With this guarantee in place, the
local class is assured that its
internal copies of the variables
accurately reflect the actual local
variables.
EDIT:
Berlin Brown says: "I posted a decompiled version of an
anonymous inner class. But to be
honest, I still don't see why the
compiler has to have that information.
Even if the field is declared final,
the field can still be null. I think
this is one of those Java quirks, you
have to declare that field
final...because that is the way it is.
There isn't a clear reason why"
The reason is to make sure that users realize that closures "close over" variables and not values. Let's suppose that there was no requirement of having final local variables. Then we could write code like:
public void doIt() {
for(int i = 0; i < 3; ++i) {
runnables.add(new Runnable() {
@Override
public void run() {
System.out.println(i);
}
});
}
run(runnables); // run each runnable
}
What do you think would be the output? If you think it would be "0 1 2" you would be mistaken since the Runnable closes over the "variable" i and not the "value" of i at that point in time and hence the output would be "2 2 2". What can be done to achieve the expected behaviour here? Two solutions: either rely on the users to have an understanding of how closures work or somehow enforce it at the language level. And it is the second option with which the language designers have gone with.
public void doIt() {
for(int i = 0; i < 3; ++i) {
final int j = i; // notice the final local variable
runnables.add(new Runnable() {
@Override
public void run() {
System.out.println(j);
}
});
}
run(runnables);
}
JFTR, I'm not saying that the second option is "the" way to go, it's just that having local variables marked as final before being used in anonymous inner classes is a big deal breaker for me. Of course, YMMV. :-)
Final makes the variable et only allowed to be assigned once. It also changes the scope of the variable and allows the function onClick visibility to et. Without the final, et is not visible within the function onClick.
The purpose of “final” keyword in JAVA can be defined in three level are Class, Method, variable
Java final variable: If you make any variable as final, you cannot change the value of final variable (It will be constant).
Java final method: If you make any method as final, you cannot override it.
Java final class: If you make any class as final, you cannot extend it.
Here is a link which discusses the final
keyword. According to the specification (section 4.12.4):
A variable can be declared final. A final variable may only be assigned to once. It is a compile time error if a final variable is assigned to unless it is definitely unassigned (§16) immediately prior to the assignment.
It also helps to understand how Java creates an anonymous inner class. How Java implements that particular class.
Java needs for that variable to be final because the compiler must know the type of that object at compile time. The compiler will then generate a field within the anonymous inner class implementation (in this case 'et').
If the type is not final, how would the compiler determine how to build the inner class implementation. Basically, by declaring the field final, you are giving the Java compiler more information.
Code that doesn't help the compiler, won't compile your anonymous inner class:
Object et;
et = a ? new Object() : new EditText();
...
With the code above, the Java compiler cannot really build the anonymous inner class.
Your code:
final EditText et=(EditText)findViewById(R.id.t);
...
new Button.OnClickListener$1(){
public void onClick(View v)<br>
{
Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText()));
startActivity(on);
}
});
...
The java compiler will create a bytecode class, an implementation of that inner class block that you provided that might look like this.
public class OnClickListener$1 {
private final EditText et ; <---- this is important
public OnClickListener$1(final et) {
this.et = et;
}
public void onClick(View v)<br>
{
Intent on=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+et.getText()));
startActivity(on);
}
}
You can test the pseudo code I provided by finding the anonymous bytecode class $1 and decompile that bytecode file.