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
Related
This was asked slightly differently earlier but asking for a yes/no answer but I'm looking for the explanation that's missing from the book (Java Concurrency in Practice), of how this apparent big mistake would be exploited maliciously or accidentally.
A final mechanism by which an object or its internal state can be
published is to publish an inner class instance, as shown in
ThisEscape in Listing 3.7. When ThisEscape publishes the
EventListener, it implicitly publishes the enclosing ThisEscape
instance as well, because inner class instances contain a hidden
reference to the enclosing instance.
Listing 3.7. Implicitly Allowing the this Reference to Escape. Don't
do this.
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
}
3.2.1. Safe Construction Practices
ThisEscape illustrates an important special case of escape—when the
this references escapes during construction. When the inner
EventListener instance is published, so is the enclosing ThisEscape
instance. But an object is in a predictable, consistent state only
after its constructor returns, so publishing an object from within its
constructor can publish an incompletely constructed object. This is
true even if the publication is the last statement in the constructor.
If the this reference escapes during construction, the object is
considered not properly constructed.[8]
[8] More specifically, the this reference should not escape from the
thread until after the constructor returns. The this reference can be
stored somewhere by the constructor so long as it is not used by
another thread until after construction. SafeListener in Listing 3.8
uses this technique.
Do not allow the this reference to escape during construction.
How would someone code against this to get to the OuterClass before it's finished constructing? What is the hidden inner class reference mentioned in italics in the first paragraph?
Please see this article. There it's clearly explained what could happen when you let this escape.
And here is a follow-up with further explanations.
It's Heinz Kabutz amazing newsletter, where this and other very interesting topics are discussed. I highly recommend it.
Here is the sample taken from the links, which show how the this reference escapes:
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
num = 42;
}
private void doSomething(Event e) {
if (num != 42) {
System.out.println("Race condition detected at " +
new Date());
}
}
}
When it gets compiled, javac generates two classes. The outer class looks like this:
public class ThisEscape {
private final int num;
public ThisEscape(EventSource source) {
source.registerListener(new ThisEscape$1(this));
num = 42;
}
private void doSomething(Event e) {
if (num != 42)
System.out.println(
"Race condition detected at " + new Date());
}
static void access$000(ThisEscape _this, Event event) {
_this.doSomething(event);
}
}
Next we have the anonymous inner class:
class ThisEscape$1 implements EventListener {
final ThisEscape this$0;
ThisEscape$1(ThisEscape thisescape) {
this$0 = thisescape;
super();
}
public void onEvent(Event e) {
ThisEscape.access$000(this$0, e);
}
}
Here the anonymous inner class created in the constructor of the outer class is converted to a package-access class that receives a reference to the outer class (the one that is allowing this to escape). For the inner class to have access to the attributes and methods of the outer class, a static package-access method is created in the outer class. This is access$000.
Those two articles show both how the actual escaping occurs and what might happen.
The 'what' is basically a race condition that could lead to a NullPointerException or any other exception when attempting to use the object while not yet fully initialized. In the example, if a thread is quick enough, it could happen that it runs the doSomething() method while num has not yet been correctly initialized to 42. In the first link there's a test that shows exactly that.
EDIT:
A few lines regarding how to code against this issue/feature were missing. I can only think about sticking to a (maybe incomplete) set of rules/principles to avoid this problem and others alike:
Only call private methods from within the constructor
If you like adrenaline and want to call protected methods from within the constructor, do it, but declare these methods as final, so that they cannot be overriden by subclasses
Never create inner classes in the constructor, either anonymous, local, static or non-static
In the constructor, don't pass this directly as an argument to anything
Avoid any transitive combination of the rules above, i.e. don't create an anonymous inner class in a private or protected final method that is invoked from within the constructor
Use the constructor to just construct an instance of the class, and let it only initialize attributes of the class, either with default values or with provided arguments
If you need to do further things, use either the builder or the factory pattern.
I'll modify the example a bit, to make it more clear. Consider this class:
public class ThisEscape {
Object someThing;
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e, someThing);
}
});
someThing = initTheThing();
}
}
Behind the scenes, the anonymous inner class has access to the outer instance. You can tell this, because you can access the instance variable someThing and, as Shashank mentioned you can access the outer instance via ThisEscape.this.
The problem is that by giving the anonymous inner class instance to the outside (in this case the EventSource object) it will also carry the ThisEscape instance with it.
What can happen bad with it? Consider this implementation of EventSource below:
public class SomeEventSource implements EventSource {
EventListener listener;
public void registerListener(EventListener listener) {
this.listener = listener;
}
public void processEvent(Event e) {
listener.onEvent(e);
}
}
In ThisEscape's constructor we register an EventListener which will be stored in the listener instance variable.
Now consider two threads. One is calling the ThisEscape constructor, while the other calls processEvent with some event. Also, let's say the JVM decides to switch from the first thread to the second one, right after the source.registerListener line and right before someThing = initTheThing(). The second thread now runs, and it will call the onEvent method, which as you can see, does something with someThing. But what is someThing? It's null, because the other thread did not finish initializing the object, so this will (probably) cause a NullPointerException, which is not actually what you want.
To sum up: be careful that you don't escape objects that have not been fully initialized (or in other words, their constructor did not finish yet). One subtle way you could inadvertently do this, is by escaping anonymous inner classes from the constructor, which will implicitly escape the outer instance, which is not fully initialized.
The key point here is that it is often easy to forget that an in-lined anonymous object still has a reference to its parent object and that's how this code fragment is exposing a not-yet-completely-initialised instance of itself.
Imagine EventSource.registerListener immediately calls EventLister.doSomething()! That doSomething will be called on an object whose parent this is incomplete.
public class ThisEscape {
public ThisEscape(EventSource source) {
// Calling a method
source.registerListener(
// With a new object
new EventListener() {
// That even does something
public void onEvent(Event e) {
doSomething(e);
}
});
// While construction is still in progress.
}
}
Doing it this way would plug the hole.
public class TheresNoEscape {
public TheresNoEscape(EventSource source) {
// Calling a method
source.registerListener(
// With a new object - that is static there is no escape.
new MyEventListener());
}
private static class MyEventListener {
// That even does something
public void onEvent(Event e) {
doSomething(e);
}
}
}
It is my understanding that the issue is not that the user can gain access to the escaped ThisEscape reference (it is, after all, said to be hidden). The issue is that because of the way the classes are compiled and executed, the JVM can see that reference and start referencing it elsewhere before the constructor has finished building the ThisEscape instance. So race conditions can result.
I have the following two classes (in two separate files).
public class Foo
{
public static class A
{
public static final boolean FLAG = false;
}
public final A A = new A();
}
public class Bar
{
void method()
{
if (Foo.A.FLAG) <<<< this is giving "Cannot make static ref to non-static field
// do something
;
}
}
My question is, why isn't the compiler able to recorgnise that by Foo.A, I meant the class A, not the member, which also happens to be named A?
This is called obscuring, an obscure feature/limitation of Java
A simple name may occur in contexts where it may potentially be
interpreted as the name of a variable, a type, or a package. In these
situations, the rules of §6.5 specify that a variable will be chosen
in preference to a type, and that a type will be chosen in preference
to a package. Thus, it is may sometimes be impossible to refer to a
visible type or package declaration via its simple name. We say that
such a declaration is obscured.
If the variable A was static, it would compile since you can can access static members on object references.
Also FLAG hasn't been initialized.
Some ways to access the flag:
<Foo_A extends Foo.A> void test1()
{
if(Foo_A.FLAG)
;
}
void test2()
{
class Foo_A extends Foo.A{}
if(Foo_A.FLAG)
;
}
-------------------------------------
import pkg.Foo.A;
public class Bar
{
void test3()
{
if(A.FLAG)
;
}
}
in these contexts, "Foo.A" can only be interpreted as a type, not a variable.
Because inner classes require an instance of the enclosing type. If you dont have an instance of Foo, A doesnt exist.
Edit - This is incorrect, but the reason why is informative. see the comments below:
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.
I have the following two classes:
public class Class1
{
public Class1 randomvariable; // Variable declared
public static void main(String[] args)
{
randomvariable = new Class1(); // Variable initialized
}
}
public class Class2
{
public static void ranMethod()
{
randomvariable.getSomething(); // I can't access the member "randomvariable" here even though it's public and it's in the same project?
}
}
I am very certain that it's a very fundamental thing I'm missing here, but what am I actually missing? The Class1 member "randomvariable" is public and so is the class and both classes are in the same project.
What do I have to do to fix this problem?
There are two problems:
Firstly, you're trying to assign a value to randomvariable from main, without there being an instance of Class1. This would be okay in an instance method, as randomvariable would be implicitly this.randomvariable - but this is a static method.
Secondly, you're trying to read the value from Class2.ranMethod, again without there being an instance of Class1 involved.
It's important that you understand what an instance variable is. It's a value associated with a particular instance of a class. So if you had a class called Person, you might have a variable called name. Now in Class2.ranMethod, you'd effectively be writing:
name.getSomething();
That makes no sense - firstly there's nothing associating this code with Person at all, and secondly it doesn't say which person is involved.
Likewise within the main method - there's no instance, so you haven't got the context.
Here's an alternative program which does work, so you can see the difference:
public class Person {
// In real code you should almost *never* have public variables
// like this. It would normally be private, and you'd expose
// a public getName() method. It might be final, too, with the value
// assigned in the constructor.
public String name;
public static void main(String[] args) {
Person x = new Person();
x.name = "Fred";
PersonPresenter.displayPerson(x);
}
}
class PersonPresenter {
// In a real system this would probably be an instance method
public static void displayPerson(Person person) {
System.out.println("I present to you: " + person.name);
}
}
As you can tell by the comments, this still isn't ideal code - but I wanted to stay fairly close to your original code.
However, this now works: main is trying to set the value of an instance variable for a particular instance, and likewise presentPerson is given a reference to an instance as a parameter, so it can find out the value of the name variable for that instance.
When you try to access randomvariable you have to specify where it lives. Since its a non-static class field, you need an instance of Class1 in order to have a randomvariable. For instance:
Class1 randomclass;
randomclass.randomvariable.getSomething();
If it were a static field instead, meaning that only one exists per class instead of one per instance, you could access it with the class name:
Class1.randomvariable.getSomething();
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.