Take the following example:
public void init() {
final Environment env = new Environment();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
env.close();
}
});
}
Firstly, where is env stored? Is it:
copied by the compiler into a hidden member variable of the inner class that references it
copied to, and referenced on, the heap
left on the stack and somehow referenced there
something else
My guess is the first option.
Secondly, do any performance issues that arise from doing this (rather than simply creating env as a member variable of the class and referencing it as such) particularly if you are creating large numbers of such inner class constructs that reference final local variables.
Yes, they are copied, which is why you have to declare the variable as final. This way, they are guaranteed to not change after the copy has been made.
This is different for instance fields, which are accessible even if not final. In this case, the inner class gets a reference to the outer instance that it uses for this purpose.
private Environment env; // a field does not have to be final
public void init() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
env.close();
}
});
}
Secondly, do any performance issues that arise from doing this?
Compared to what? You need to have the field or variable around for your inner class to work, and a copy is a very efficient way. It is only a "shallow" copy anyway: just the reference to the (in your example) Environment is copied, not the Environment itself.
Related
Working with anonymous innerclasses in java,you have to declare the variables of enclosing class which you are using in the anonymous innerclass as final. Ok i got it that why this must be done from
Cannot refer to a non-final variable inside an inner class defined in a different method
but also the answerer says that
"By making lastPrice and price final, they are not really variables
anymore, but constants. The compiler can then just replace the use of
lastPrice and price in the anonymous class with the values of the
constants (at compile time, ofcourse), and you won't have the problem
with accessing non-existent variables anymore"
This made me to wander that is the final keyword working like as Macros are in C\C++.Till now, I was using final for variables in a way that whenever I will try to modify them(accidentally) I will be getting an error that You can't modify it as it is declared as final.But this replacement thing is not clear to me.
Question: According to the selected answer from the above link answerer says
This is why it doesn't work:
The variables lastPrice and price are local variables in the main()
method. The object that you create with the anonymous class might last
until after the main() method returns.
When the main() method returns, local variables (such as lastPrice and
price) will be cleaned up from the stack, so they won't exist anymore
after main() returns.
But the anonymous class object references these variables. Things
would go horribly wrong if the anonymous class object tries to access
the variables after they have been cleaned up.
**
Where this storage is taking place for replacement later?Who is taking care of it?final variables are just replaced by values?
**
No, this is not like macros in C++. The difference is that macros are evaluated at compile time and the preprocessor replace the macro with its definition.
final variables on the other hand can be computed at run time. Once set, though, the value cannot change at a later time. This constraint is what makes it possible to use the value in an inner class.
Let's look at an example to make this more clear:
public void func(final int param) {
InnerClass inner = new InnerClass() {
public void innerFunc() {
System.out.println(param);
}
}
inner.innerFunc();
}
Note that param can be set at run time by passing different values to it. But each time func() is called, a new InnerClass object is created and captures the current value of param which is guaranteed to never change because it is declared as final.
In a different situation where the variable is constant, then the compiler can replace the value at compile time. However, this isn't special for inner classes because constants are replaced at compile time no matter where they are used.
The moral of the story is that an anonymous inner class can access any final variable whether or not it is a compile time constant or calculated at run time.
#Butterflow from Brian Goetz:
Declaring a final field helps the optimizer make better optimization decisions, because if the compiler knows the field's value will not change, it can safely cache the value in a register. final fields also provide an extra level of safety by having the compiler enforce that a field is read-only.
You can find here the full article about the keyword final
With anonymous classes, you are actually declaring a "nameless" nested class. For nested classes, the compiler generates a new standalone public class with a constructor that will take all the variables it uses as arguments (for "named" nested classes, this is always an instance of the original/enclosing class). This is done because the runtime environment has no notion of nested classes, so there needs to be a (automatic) conversion from a nested to a standalone class.
Take this code for example:
public class EnclosingClass {
public void someMethod() {
String shared = "hello";
new Thread() {
public void run() {
// this is not valid, won't compile
System.out.println(shared); // this instance expects shared to point to the reference where the String object "hello" lives in heap
}
}.start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
}
That won't work, because this is what the compiler does under the hood:
public void someMethod() {
String shared = "hello";
new EnclosingClass$1(shared).start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
The original anonymous class is replaced by some standalone class that the compiler generates (code is not exact, but should give you a good idea):
public class EnclosingClass$1 extends Thread {
String shared;
public EnclosingClass$1(String shared) {
this.shared = shared;
}
public void run() {
System.out.println(shared);
}
}
As you can see, the standalone class holds a reference to the shared object, remember that everything in java is pass-by-value, so even if the reference variable 'shared' in EnclosingClass gets changed, the instance it points to is not modified, and all other reference variables pointing to it (like the one in the anonymous class: Enclosing$1), will not be aware of this. This is the main reason the compiler forces you to declare this 'shared' variables as final, so that this type of behavior won't make it into your already running code.
Now, this is what happens when you use an instance variable inside an anonymous class (this is what you should do to solve your problem, move your logic to an "instance" method or a constructor of a class):
public class EnclosingClass {
String shared = "hello";
public void someMethod() {
new Thread() {
public void run() {
System.out.println(shared); // this is perfectly valid
}
}.start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
}
This compiles fine, because the compiler will modify the code, so that the new generated class Enclosing$1 will hold a reference to the instance of EnclosingClass where it was instantiated (this is only a representation, but should get you going):
public void someMethod() {
new EnclosingClass$1(this).start();
// change the reference 'shared' points to, with a new value
shared = "other hello";
System.out.println(shared);
}
public class EnclosingClass$1 extends Thread {
EnclosingClass enclosing;
public EnclosingClass$1(EnclosingClass enclosing) {
this.enclosing = enclosing;
}
public void run() {
System.out.println(enclosing.shared);
}
}
Like this, when the reference variable 'shared' in EnclosingClass gets reassigned, and this happens before the call to Thread#run(), you'll see "other hello" printed twice, because now EnclosingClass$1#enclosing variable will keep a reference to the object of the class where it was declared, so changes to any attribute on that object will be visible to instances of EnclosingClass$1.
For more information on the subject, you can see this excelent blog post (not written by me): http://kevinboone.net/java_inner.html
So I am writing a very large java code, within this code I want it to output files in a particular file format. In this instance it is going to be a simple .txt file.
The data I am outputting is a series of coordinates, these coordinates have undergone rotation using an angle that is determined by the user prior to this code section.
The code to write the file is obviously in a static method but the angle I am calling is a non-static variable... how do I call this and get it to work?
Basically you have to pass an instance of the object containing the non-static variable to the static function and access it there.
That would look something like this:
public class ObjectToBeWritten {
private int nonStaticVariable;
public ObjectToBeWritten() {
// ...
}
public int getNonStaticVariable() {
return nonStaticVariable;
}
public static void outputToTxt(ObjectToBeWritten object) {
nonStaticVariable = object.getNonStaticVariable();
// ...
}
}
Then you just call ObjectToBeWritten.outputToTxt(object) with the object that contains the non-static variable.
Non static means that it belongs to some class instance(object). So pass this object to your static method and/or create those objects inside it.
you should know non-static method belongs to Object ,but static method belongs to Class.Therefore the getNonStaticVariables method and nonStaticVariable should be static or change the outputToTxt to non-static.
My first thought is that perhaps either your non-static variable or your static method belong somewhere else.
When a class hold variable, non-static contents, it's probably a bad idea to provide static accessor functions that use that variable. I think the best solution is to separate the two, giving the responsibility of storing the mutable data in some Data Provider class that can provide a DEFENSIVE COPY of this variable. Perhaps you don't see the need for it because your example deals with a primitive value. But, if you were to change that to some object reference, you could run into all sorts of problems; one of which is that your code will not be thread-safe.
public class MyDataProvider {
private Object nonStaticVariable;
public MyDataProvider () {
// ...
}
public Object getNonStaticVariable() {
Object copy = new Object();
// copy the internals from nonStaticVariable to copy
return copy;
}
}
Then, your utility class can use the copy of nonStaticVariable to do its work...
public class MyUtilityClass {
public static void outputToTxt(Object nonStaticVariableCopy) {
// do your work
}
}
This solution solves all those problems and is much more robust:
Allows a non-static variable to be used by a static method
Your code will be thread-safe because you are using a copy of the non-static variable instead of the original variable.
Separation of concerns: Your utility class doesn't store any variables; thus all methods of the utility class can be static (like Java's Math class), and your Data Provider can be the container that holds your variables.
This question already has answers here:
Cannot refer to a non-final variable inside an inner class defined in a different method
(20 answers)
Why are only final variables accessible in anonymous class?
(15 answers)
Closed 9 years ago.
Given the following inner class (IsSomething) within a method:
public class InnerMethod {
private int x;
public class Something {
private int y;
public void printMyNumber(double x)
{
class IsSomething extends Something {
public void print() {
System.out.println(x);
}
}
}
}
}
Why does the X variable has to be FINAL to make it work..?
(I'm talking ofc about the X parameter of the "printMyNumber" function.)
The difference is between local 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.
Final local variables
There are two reasons I know for making a local variable or a
parameter final. The first reason is that you don't want your code
changing the local variable or parameter. It is considered by many to
be bad style to change a parameter inside a method as it makes the
code unclear. As a habit, some programmers make all their parameters
"final" to prevent themselves from changing them. I don't do that,
since I find it makes my method signature a bit ugly.
The second reason comes in when we want to access a local variable or
parameter from within an inner class. This is the actual reason, as
far as I know, that final local variables and parameters were
introduced into the Java language in JDK 1.1.
public class Access1 {
public void f() {
final int i = 3;
Runnable runnable = new Runnable() {
public void run() {
System.out.println(i);
}
};
}
}
Inside the run() method we can only access i if we make it final in the outer class. To understand the reasoning, we have to
look at what the compiler does. It produces two files, Access1.class
and Access1$1.class. When we decompile them with JAD, we get:
public class Access1 {
public Access1() {}
public void f() {
Access1$1 access1$1 = new Access1$1(this);
}
}
and
class Access1$1 implements Runnable {
Access1$1(Access1 access1) {
this$0 = access1;
}
public void run() {
System.out.println(3);
}
private final Access1 this$0;
}
Since the value of i is final, the compiler can "inline" it into the inner
class. It perturbed me that the local variables had to be final to be
accessed by the inner class until I saw the above.
When the value of the local variable can change for different
instances of the inner class, the compiler adds it as a data member of
the inner class and lets it be initialised in the constructor. The
underlying reason behind this is that Java does not have pointers, the
way that C has.
Consider the following class:
public class Access2 {
public void f() {
for (int i=0; i<10; i++) {
final int value = i;
Runnable runnable = new Runnable() {
public void run() {
System.out.println(value);
}
};
}
}
}
The problem here is that we have to make a new local data member each time we go through the for loop, so a thought I had today
while coding, was to change the above code to the following:
public class Access3 {
public void f() {
Runnable[] runners = new Runnable[10];
for (final int[] i={0}; i[0]<runners.length; i[0]++) {
runners[i[0]] = new Runnable() {
private int counter = i[0];
public void run() {
System.out.println(counter);
}
};
}
for (int i=0; i<runners.length; i++)
runners[i].run();
}
public static void main(String[] args) {
new Access3().f();
}
}
We now don't have to declare an additional final local variable. In fact, is it not perhaps true that
int[] i is like a common C pointer to an int? It took me 4 years to
see this, but I'd like to hear from you if you have heard this idea
somewhere else.
The methods in an anonymous class don't really have access to local variables and method parameters. Rather, when an object of the anonymous class is instantiated, copies of the final local variables and method parameters referred to by the object's methods are stored as instance variables in the object. The methods in the object of the anonymous class really access those hidden instance variables.
From the JLS :
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 (ยง16) before the body of the inner class.
This is because the lifetime of an instance of a local class can be much longer than the execution of the method in which the class is defined. For this reason, a local class must have a private internal copy of all local variables it uses (these copies are automatically generated by the compiler). The only way to ensure that the local variable and the private copy are always the same is to insist that the local variable is final.
So, here's what I understand: Java doesn't support closures, so it sort of copies the variables from the containing scope into the nested scope, so they are available later. Because this is a copy, there is no way to synchronize the original and the copy, and the variable is forced to be final so the developer cannot change it and expect it to be updated. This understanding is partly taken form these answers
And that brings us to this code working:
public class SimpleClosure {
public static void main(String[] args) {
new SimpleClosure().doStuff();
}
public void doStuff() {
final int number = 3;
new Thread() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Integer.toString(number));
}
}.start();
}
}
So, great. Now, the thing is, a final modifier only prevents me from changing the object that the variable points to, but I can change the object without problems. If a "copy" was made, then changes to the object contents should not be reflected. The question, therefore is, why does the following code work?
import java.util.HashMap;
import java.util.Map;
public class StretchingClosure {
public static void main(String[] args) {
new StretchingClosure().doStuff();
}
public void doStuff() {
final Map<String, String> map = new HashMap<String, String>();
map.put("animal", "cat");
new Thread() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(map.get("animal")); // Outputs dog See (1)
}
}.start();
map.put("animal", "dog");
}
}
Needless to say, I'm missing something, or I'm oversimplyfying the way the compiler handles these cases. Could anyone please enlighten me?
(1): as pointed out by #trashgod, the output is true most of the time on most of the platforms, but it's not guaranteed due to the lack of synchronization. This is good enough for the example, but bad practice in general.
Don't confuse the variable with the object: the reference from the local variable is indeed copied, but it still refers to the same object, in your case the map. There is a widely known idiom to work around the final restriction, involving arrays:
final int[] x = {1};
... use in an anonymous instance...
System.out.println(x[0]);
The comment // Outputs dog is misleading in the sense that it's only true most of the time on most platforms. One second is plenty of time to update the Map on the initial thread, but nothing guarantees visibility of the updated value in the anonymous thread unless access to the shared data is correctly synchronized. See Memory Consistency Properties for a nice summary of relevant features in java.util.concurrent.
Java does the same thing there as it does with regular method parameters:
Method parameters are passed by reference value, so while you cannot change the object itself, if it is mutable and provides ways of mutating its inner state, you can change that state. You cannot change a string, but you can change the items inside a collection, for example.
The reference is passed by value = the reference is copied. The object itself isn't.
Anonymous classes do not get copies of variables, but rather copies of references to the objects, that's why after 1s you get the "right" value which was changed outside the anonymous class.
I was wondering, whether the following code are safe.
public class GUIBundle {
// The technique known as the initialization on demand holder idiom,
// is as lazy as possible.
// http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
//private static class BundleHolder {
// private static final ResourceBundle bundle = ResourceBundle.getBundle("org.yccheok.jstock.data.gui");
//}
private static final ResourceBundle bundle = ResourceBundle.getBundle("org.yccheok.jstock.data.gui");
private GUIBundle() {
}
public static String getString(String key) {
// return BundleHolder.bundle.getString(key);
return bundle.getString(key);
}
}
public class SellPortfolioChartJDialog extends javax.swing.JDialog {
private static final String[] cNames = new String[] {
GUIBundle.getString("BuyPortfolioTreeTableModel_NetGainValue")
};
}
Since cNames is within static scope, is it safe for it to access static bundle? Does it make any different whether I am using lazy initialization technique?
I remember I came across an article (I lost the article anyway) talking about nondeterministic of initialization order of static variables. I am not sure whether the nondeterministic of initialization order of static variables, applied to the above case?
I believe the nondeterministic initialization order of static variables (in different compilation units) is a C/C++ "feature". In Java, static variables are initialized when their class is loaded, and within a single class in their order of declaration. So the order is deterministic (at least in a single threaded environment).
This guarantees that what you intend to do should work: when GUIBundle is first referenced, the classloader loads it and initializes bundle too. The call to GUIBundle.getString() happens only after the class initialization is done.
That works just fine. I got it to compile by keeping the principle the same but using different classes (I didn't want to bother getting your jars... :-).
Obviously there are some small problems, like how you declare your String[] needs to be
private static final String[] cNames = new String[] {
GUIBundle.getString("BuyPortfolioTreeTableModel_NetGainValue")
};
}
Other than that, it works just fine. The key to using statics in other statics is the order they're declared. You can't do this
static Foo b = a;
static Foo a = new Foo();
I think its perfectly safe, You see because the when
GUIBundle.getString
is used in your JDialog subclass, the JVM will completely initialize (see java language spec loading, linking and initialization) the class GUIBundle before calling the method getString on it, which will initialize all the class (static) initializers in the class GUIBundle.
Edit: Read more about this in VM spec:
http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#16491
To me it's safe.
bundle is initialized right after GUIBuilder is loaded and therfore before getString is called for the first time.