I have a method that uses a SwingWorker. Part of the code is shown below:
public class mySocket {
public void writePacket(final String packet) {
// schedules execution on the single thread of the executor (so only one
// background operation can happen at once)
//
executor.execute(new SwingWorker<String, Void>() {
#Override
protected String doInBackground() throws Exception {
// called on a background thread
System.out.println("writing out this packet->" + packet + "
<-");
out.println(packet);
String thePacket = readPacket();
return thePacket;
}
..................
My questions are about the signature of the writePacket method. The variable packet must be declared final or the compiler complains because SwingWorker is an inner class. This raises the following questions about how and when I can assign values to this variable:
Final to me means that the variable can only be assigned a value once. But because the declaration is part of the signature of a method, I don't know what this means in this context.
I always assumed that final variables were assigned values when the class was instantiated but here it is assigned when the method is called. Does the variable passed to the method also need to be declared final and assigned in the class's constructor for this to work?
Can I call the method more than once with different values for packet or because the variable is declared final, does this mean that if I want to call the method with different values, I need to reinstantiate the class for each new value of the variable packet ?
Thanks in advance for your help.
Elliott
1. Final to me means that the variable can only be assigned a value once. But because the declaration is part of the signature of a method, I don't know what this means in this context.
It just means that you can't reassign a new value to the variable packet.
2. I always assumed that final variables were assigned values when the class was instantiated but here it is assigned when the method is called. Does the variable passed to the method also need to be declared final and assigned in the class's constructor for this to work?
You can have local final variables as well. Same rules applies, but they are unrelated to constructor / this reference.
3. Can I call the method more than once with different values for packet or because the variable is declared final, does this mean that if I want to call the method with different values, I need to reinstantiate the class for each new value of the variable packet ?
You can call the method several times with different values. The packet variable is like a local variable. and No, you don't need to reinstantiate the class for each value / call.
Further SO reading:
Cannot refer to a non-final variable inside an inner class defined in a different method
Cannot refer/modify non-final variable in an innerclass
access to variable within inner class in java
The inner class can only reference final variables because the variable that is wantd is actually passed to the inner class ctor as a parameter. If the variable was not final, and changed after the inner class was created, it would no longer be holding onto the current but previous variable. To avoid such strangeness and to keep things simple, variables/parameters must be final for an inner class to read.
Final to me means that the variable can only be assigned a value
once. But because the declaration is part of the signature of a
method, I don't know what this means in this context.
It means the same thing, you can't re-assign the variable.
// this compiles
public void foo(String bar){
bar = "xyz";
}
// this doesn't
public void foo(final String bar){
bar = "xyz";
}
I always assumed that final variables were assigned values when
the class was instantiated but here it is assigned when the method is called.
No, local variables can also be final, and parameters too. They are assigned once per scope (block or method level).
Does the variable passed to the method also need to be
declared final and assigned in the class's constructor for this to
work?
No, that's totally irrelevant
Can I call the method more than once with different values for packet
or because the variable is declared final, does this mean that if I
want to call the method with different values, I need to reinstantiate
the class for each new value of the variable packet ?
No, see above. It's a new variable for each method call.
Final to me means that the variable can only be assigned a value once. But because the declaration is part of the signature of a method, I don't know what this means in this context.
Same thing. It means you cannot re-assign a new value to the local variable that contains the parameter (that is considered bad practice anyway).
I always assumed that final variables were assigned values when the class was instantiated but here it is assigned when the method is called
That first part is true for final instance variables, not for local variables.
But the idea is the same: They need to be assigned a value and it can happen only once.
Can I call the method more than once with different values for packet or because the variable is declared final, does this mean that if I want to call the method with different values, I need to reinstantiate the class for each new value of the variable packet ?
You can call it many times. The parameter being declared final has no impact to code calling of the method (just for its implementation).
Related
Inner classes only have access to final or effectively final variables. I don't understand though, why an instance variable can be accessed no matter what, but local variables and method parameters need to be at minimum effectively final?
Consider the following code:
public class BookStore {
private static final int taxId = 300000;
public String name;
public String searchBook(final String criteria) {
int count = 0;
int sum = 0;
// name = ""; I can uncomment this -> no compile error
class Enumerator {
String interate(int k) {
System.out.println(name);
System.out.println(sum);
return "";
}
}
// sum++; If I uncomment this, a compile error will be thrown.
return "";
}
}
Why is it necessary that local variables + method arguments need to be effectively final?
It’s all about the value which is captured when the instance is created. Inner classes in an instance context always capture the immutable outer this reference¹, through which the instance fields can be accessed, mutable or not. In contrast, local variables can only be captured by their value, hence, the variable must not change, to be consistent with the captured value.
This is a design decision. Technically, it would be no problem to a) allow subsequent mutations that are not reflected by the inner class’ state or b) wrap every shared local variable into an object to allow mutations like with instance fields of the outer class, but neither, allowed inconsistency nor local variables that aren’t actually local, were deemed acceptable by the language designers.
¹ This differs from lambda expressions which only capture this when actually accessing instance variables
It's because of the scope of the local variables. Their scope is the method in which they are declared. Once execution has left the method, they are no longer valid. However, an inner class such as your Enumerator class can live on past the method execution, e.g. by returning a reference to a class instance.
Thus, the Enumerator class and its methods can be accessed outside of the method in which it is declared. At that point, it needs to assume that the local variables it referenced have the same value they had when execution instantiated the class.
For instance variables, the scope of these and of the inner class is the same - they are both available as long as the parent class instance exists.
Not actually global variables, but just variables that are class-wide.
For example, I have this initialization:
MyObj obj = new MyObj();
And then I have this method:
public void Foo(){
obj.doSomething;
}
Let's say that I'm not able to use a constructor(this is pertaining to android). Will the variable be guaranteed to always be initialized before any methods in the class is called?
(To be clear: 1) Java doesn't have global variables. 2) Java has class (i.e. static) fields and instance fields, as well as local variables. 3) The example appears to show an instance field, so I am assuming that is what you are asking about.)
Are java global variables guaranteed to initialize first?
Yes. Except in pathological cases that I will explain below.
When an object is created, the following things are done in the following order:
The object is allocated on the heap with the correct object type, and all instance fields are "default initialized" to zero, false or null.
The expressions in the super(...) or this(...) are evaluated and the constructor for the next class up the chain is called. (This recurses up the chain constructor, so that the Object constructor gets executed first.)
The instance variable initializers and any instance initializer blocks are executed in order.
The body of the constructor is executed.
The constructor returns.
All of this happens when you execute new SomeClass(...).
So, in your example (as written), you can sure that the instance variable obj will be initialized before your method is called.
Now for the pathological cases. Consider this:
public class Foo {
private int a = someMethod();
private int b = 42;
public Foo() {
}
private int someMethod() {
return this.b;
}
}
In this case, the initializer for a will call someMethod before b has been initialized, and hence someMethod will return the default initial value of b ... zero. You could also "implement" the pathological example using an instance initialize block. However, if you called someMethod within the Foo constructor, you can be sure that the instance variable's initializer will have been executed.
Indeed there are other pathological cases to consider. If the implementation of someMethod in the above were to call a method in another class, passing this as an argument, then the other class could call methods on the partially initialized Foo instance. (This is called unsafe publication. It is particularly insidious if the partially initialized instance can be accessed by another thread, because that invalidates various Java memory model guarantees.)
Will the variable be guaranteed to always be initialized before any methods in the class is called?
Yes. You are correct. It's already initialized since it's declared even on top of constructor and ready for the use later.
And it's up to you, where you are going to use that instance member, weather in constructor or in methods later, but it's guaranteed to initialize before the constructor called.
First of all, it's not a global variable. It's an instance variable. It is guaranteed to be initialized before the constructor is called, so it is guaranteed to be initialized when Foo is called.
That is what Myobj() is. It is a default constructor and it gets overridden if you explicitly define a constructor in your class.
All variables gets its memory as soon as You make its Object (Reference Variable) and class get its space as soon as the new keyword gets compiled even before your statement MyObj obj = new MyObj(); gets compiled.
Is there a difference between assigning values to variables outside of any method, and assigning these values within a constructor?
Looking at Oracle's Java tutorial, they have:
public class Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue) {
cadence = newValue;
}
is this any different from saying/why didn't they just say:
Bicycle(){
int cadence = 0;
}
If you declare the variable in your constructor, it will be local to the constructor and not visible anywhere else in your class.
If you declare a variable inside a constructor, this variable can only be accessed inside this constructor. But, you can create a variable on your class, and access it on your constructor or method.
Well if you define a variable in a constructor, it is local to the constructor. But a variable in the class is part of class' state.
But if you mean:
class A {
int i = 1;
...
}
vs
class B {
int i;
B() {
i = 1;
}
...
}
the difference is: in the first case, the default value of i is 1, in all instances, but in second case the default value of i is 1 if the shown constructor is called, maybe in other constructors other default value be something else (or 0 if nothing is assigned to i).
When you create object instance, global variables will be initialized. You can (but not have to) change some of them in constructor.
I think you mean
Bicycle() {
cadence = 0;
}
In the constructor : it will be Local variable
Java contains the following types of variables:
Instance Variables (Non-static fields): In object oriented programming, objects store their individual states in the "non-static fields" that is declared without the static keyword. Each object of the class has its own set of values for these non-static variables so we can say that these are related to objects (instances of the class).Hence these variables are also known as instance variables. These variables take default values if not initialized.
Class Variables (Static fields): These are collectively related to a class and none of the object can claim them its sole-proprietor . The variables defined with static keyword are shared by all objects. Here Objects do not store an individual value but they are forced to share it among themselves. These variables are declared as "static fields" using the static keyword. Always the same set of values is shared among different objects of the same class. So these variables are like global variables which are same for all objects of the class. These variables take default values if not initialized.
Local Variables: The variables defined in a method or block of code is called local variables. These variables can be accessed within a method or block of code only. These variables don't take default values if not initialized. These values are required to be initialized before using them.
Parameters: Parameters or arguments are variables used in method declarations.
The constructor is like any other method. Variables that are declared inside it are available only within it, and they'll get destroyed when you go out of scope.
The difference in this case is that you are not only assigning the variable in the constructor (in the second case). You are also declaring it there. Thus, the variable is local to the constructor and not visible from outside.
I think your question is: If we can give a default value to the variable(of a class) directly, why to give it inside a constructor instead. If that's the question, then I think its because the values in the variable would be available even when the objects are not initialized which is not a healthy practice and does not make much sense. Instead, giving values inside a constructor would not only be hidden but would also obey oops rules for java.
When we have a final instance variable of a class, is it instantiated for each object created of the class or just created once and referred?
And what is the case if the final variable is a local class variable??
The final modifier simply indicates that the variable can be assigned once and never again. It has no impact on the instantiation; the rules are the same as for normal variables. All the final modifier does is prevent the value being assigned a second time.
Examples below.
private final List myList = new ArrayList();
The list will be instantiated each time this is run, i.e. each time the enclosing class is instantiated.
public void bob() {
final List myList = new ArrayList();
}
The list will be instantiated each time this is run, i.e. each time the method bob is invoked.
private static final List MY_LIST = new ArrayList();
Again, the list will be instantiated each time this is run. As this is also a static field initializer, this code will be run when the class is first loaded. So, for simplistic programs, this will be run once -- in scenarios where multiple class loaders are in play (e.g. app-servers etc), however, this will be run once each time the class is loaded in a new class loader.
Final variables is instantiated for each instance of the class. The values once assigned to them may not be changed. These variables may be initialized once, either via an initializer or an assignment statement.
What you are referring to are the static variables. These variable is not attached to a particular object, but rather to the class as a whole. They are allocated when the class is loaded.
Taking these two together, you can have a static final variable for the class. This basically means that the value assigned to the variable once assigned is constant and that it would be attached to a class rather than an instance of the class.
Instance variables, class variables, and local variables are used to refer to three different things, so calling a variable an "instance variable of a class," or "local class variable" is confusing.
An instance variable belongs to an object. Whether it's final or not, space is allocated in every instance for it. If it's final, a value must be assigned during construction, and the variable can be assigned only once.
A class variable belongs to the class as a whole. There's only one variable, regardless of the number of objects of that class, and all instances can refer to it. Declaring a variable as static means that it belongs to the class. Like instance variables, a static class variable can be declared final. Then it must be assigned a value once and only once when the class is initialized.
A local variable is declared within a method, and the variable occupies space in the method stack frame—although that variable may hold a pointer to an object in the heap. Local variables can be final, which means they can be assigned only once. Also, if a local variable is final, it can be referenced by inner classes instantiated in the method.
Variables are not the ones that are instantiated. Classes are instantiated. Variables are initialized. Instance variables must be initialized by the time the the object is constructed and if they are final you won't be able to reassign values to them. If it's an instance variable then each instance of the class will have it's own copy, otherwise if it's static then there will be only one copy which will belong to the class itself.
There are some topics on Stack Overflow on the compiler error Cannot refer to a non-final variable message inside an inner class defined in a different method and the solution is "declare it as final and you're done", but with this theoretical question I would like to inspect what is the logical reason why this code cannot compile:
private void updateStatus(String message) {
Runnable doUpdateStatus = new Runnable() {
public void run() {
/* do something with message */
}
}
/* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
}
(solution: declare message as final) whereas this one does:
private String enclosingClassField;
private void updateStatus() {
Runnable doUpdateStatus = new Runnable() {
public void run() {
/* do something with enclosingClassField */
}
}
/* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
}
I'm really confused. enclosingClassField is not final, it can change every time many times, whereas the poor message argument of updateStatus can only change within its method body, and is instead blamed by the compiler ;)
Even the compiler error is misleading to me. Cannot refer to a non-final variable message inside an inner class defined in a different method: Different from what? Isn't message defined in the same method as the inner class? Isn't enclosingClassField instead defined outside the method? Uhm...
Can someone point me to the correct interpretation of this matter? Thanks.
The difference is between local (method) variables vs class member variables. A member variable exists during the lifetime of the enclosing object, so it can be referenced by the inner class instance. A local variable, however, exists only during the method invocation, and is handled differently by the compiler, in that an implicit copy of it is generated as the member of the inner class. Without declaring the local variable final, one could change it, leading to subtle errors due to the inner class still referring to the original value of that variable.
Update: The Java Specialists' Newsletter #25 discusses this in more detail.
Even the compiler error is misleading to me. Cannot refer to a non-final variable message inside an inner class defined in a different method: Different from what?
From the inner class' run method I believe.
The reason is that Java doesn't support closures. There are no JVM commands to access local variable from outside the method, whereas fields of class can be easily accessed from any place.
So, when you use final local variable in an inner class, compiler actually passes a value of that variable into constructor of the inner class. Obviously, it won't work for non-final variables, since they value can change after construction of the inner class.
Fields of containing class don't have this problem, because compiler implicitly passes a reference to the containing class into the constructor of the inner class, thus you can access its fields in a normal way, as you access fields of any other class.
three types of things: instance variables, local variables,and objects:
■ Instance variables and objects live on the heap.
■ Local variables live on the stack.
Inner class object cannot use the local variables of the method in which the local inner class is defined.
because use local variables of the method is the local variables of the method are kept on the stack and lost as soon as the method ends.
But even after the method ends, the local inner class object may still be alive on the heap. Method local inner class can still use the local variables that are marked final.
final variable JVM takes these as a constant as they will not change after initiated . And when a inner class try to access them compiler create a copy of that variable into the heap and create a synthetic field inside the inner class so even when the method execution is over it is accessible because the inner class has it own copy.
synthetic field are filed which actually doesn't exist in the source code but compiler create those fields in some inner classes to make those field accessible.
The value you use must be final, but the non-final fields of a final reference can be changed. Note: this is implicitly a final reference. You cannot change it.
private String enclosingClassField;
private void updateStatus() {
final MutableClass ms = new MutableClass(1, 2);
Runnable doUpdateStatus = new Runnable() {
public void run() {
// you can use `EnclosingClass.this` because its is always final
EnclosingClass.this.enclosingClassField = "";
// shorthand for the previous line.
enclosingClassField = "";
// you cannot change `ms`, but you can change its mutable fields.
ms.x = 3;
}
}
/* do something with doUpdateStatus, like SwingUtilities.invokeLater() */
}