Java Forum / General / November 2006
Why must and must not be "final" ?
NeoGeoSNK - 14 Nov 2006 03:13 GMT Hello, I have two questions, why inner class can only access "final" argument outside the inner class? and why Java applet's init() method can't access any "final" fields? example: public class AppletGui extends JApplet { .........
final JTextField textvalue;
..........
public void init(){ ..........
textvalue = new JTextField(25); //this will encounter a compiled time error "the final field AppletGui.textvalue can not be assigned } }
any suggestions are appreciated. ^ ^ Thanks NeoGeoSnk
Daniel Pitts - 14 Nov 2006 04:59 GMT > Hello, > I have two questions, why inner class can only access "final" argument [quoted text clipped - 20 lines] > Thanks > NeoGeoSnk Its purely to reenforce to the programmer what really is happening.
The value of your parameters/variables which are used in your anonymouse class are copied at the time that the object is created (they are actually hidden final fields, I believe). If you were to change the value later, that would be more confusing than having to know that they are just "final".
NeoGeoSNK - 14 Nov 2006 05:46 GMT "Daniel Pitts 写道: "
> > Hello, > > I have two questions, why inner class can only access "final" argument [quoted text clipped - 28 lines] > change the value later, that would be more confusing than having to > know that they are just "final". Thanks a lot, and you mean this restriction only effective when a inner class is anonymouse? and not for all inner class?
Chris Uppal - 14 Nov 2006 13:02 GMT > and you mean this restriction only effective when a inner class is > anonymouse? and not for all inner class? it applies to all inner classes whether anonymous or not. You cannot /really/ access a variable in method from any other code, so the Java compiler fakes it by copying the value into the instance of the inner class -- which, as Daniel says -- is why the compiler insists that you have declared that variable "final", to ensure that you know what you are doing.
-- chris
Andreas Leitgeb - 14 Nov 2006 16:59 GMT >> and you mean this restriction only effective when a inner class is >> anonymouse? and not for all inner class? [quoted text clipped - 3 lines] > says -- is why the compiler insists that you have declared that variable > "final", to ensure that you know what you are doing. An extra note: This doesn't mean that you couldn't share non-final references between the outer and inner class! Just wrap it up into some container-class.
Simple example:
class Outer { final TextField[] tf = new TextField[1]; class Inner { // use and modify tf[0] at will. } void init() { // use and modify tf[0] at will. } }
Thomas Hawtin - 14 Nov 2006 17:34 GMT > An extra note: > This doesn't mean that you couldn't share non-final [quoted text clipped - 14 lines] > } > } I'm not sure how useful an example that is. IIRC, it does mean (from 1.5) that you can guarantee that tf[0] is non-null, even with unsafe publishing. For local classes you can do much the same (but use AtomicReference):
String foo(String arg) { final AtomicReference<String> argRef = new AtomicReference<String>(arg);
new Object() { void bar() { argRef.set('<'+argRef.get()+'>'); } }.bar();
return argRef.get(); }
But please don't. :)
Tom Hawtin
NeoGeoSNK - 23 Nov 2006 04:57 GMT "Thomas Hawtin 写道: "
> > An extra note: > > This doesn't mean that you couldn't share non-final [quoted text clipped - 36 lines] > > Tom Hawtin Thanks Tom Hawtin And I think AtomicReference is more complex than Inner class:)
Mark Rafn - 14 Nov 2006 17:53 GMT >>> and you mean this restriction only effective when a inner class is >>> anonymouse? and not for all inner class?
>> it applies to all inner classes whether anonymous or not. Not true. Non-anonymous classes aren't declared inside a method, so have no access to local variables, final or not. Class members don't need to be final to be accessed from an inner class.
>An extra note: This doesn't mean that you couldn't share non-final >references between the outer and inner class! Just wrap it up into some >container-class.
>Simple example: >class Outer { [quoted text clipped - 8 lines] > } >} This isn't necessary for member variables. Just make them non-final and all is well. It's an ugly but effective workaround when an anonymous inner class needs access to local variables or parameters that you want to change. -- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Andreas Leitgeb - 14 Nov 2006 19:17 GMT >>class Outer { >> final TextField[] tf = new TextField[1]; >> ... >>}
> This isn't necessary for member variables. Just make them non-final and all > is well. It's an ugly but effective workaround when an anonymous inner class > needs access to local variables or parameters that you want to change. trapped. I mixed up the context while writing the followup.
I meant: void myFunc() { final TextField[] tf = new TextField[1]; new Object() { void foo() { tf[0]=<whatever>; } }.foo(); // now tf[0] is <whatever>. }
AtomicReference appears to me like overkill in this respect, since we're talking about local variables, that are "rarely" (that is: never ever) shared among threads...
Thomas Hawtin - 14 Nov 2006 19:59 GMT > AtomicReference appears to me like overkill in this respect, > since we're talking about local variables, that are "rarely" > (that is: never ever) shared among threads... The intent is clearer than using an array of length one.
Who cares that they are thread-safe? It isn't going to make much difference to performance. They don't need to do bounds checking, for instance. Compiler optimisation can eliminate overheads of either.
Why can't you share objects that are referred to by local variables between threads? java.awt.EventQueue.invokeLater, for instance.
Tom Hawtin
Andreas Leitgeb - 15 Nov 2006 12:11 GMT >> AtomicReference appears to me like overkill in this respect, >> since we're talking about local variables, that are "rarely" >> (that is: never ever) shared among threads... > The intent is clearer than using an array of length one. Most probably it's up to programmer's taste.
> Why can't you share objects that are referred to by local variables > between threads? java.awt.EventQueue.invokeLater, for instance. Ok, I had the reference itself in mind. Surely, the AtomicReference or the array both could be shared, but they entered the scene as a replacement for a must-be-final local reference, so it's not likely that the existing program logic passes them anywhere else.
Daniel Pitts - 14 Nov 2006 20:48 GMT > >>class Outer { > >> final TextField[] tf = new TextField[1]; [quoted text clipped - 18 lines] > since we're talking about local variables, that are "rarely" > (that is: never ever) shared among threads... This method seems bad. If an anonymouse-inner class has to modify some state somewhere, have it call a method to do so, or make it non-anonymouse, and have it have its own state.
void myFunc() { new Object() {void foo() {setTextField(<whatever>); } }.foo() }
or class Outter { static class MyFooable { TextField textField; void foo() { textField = <whatever>; } } void myFunc() { MyFooable mf = new MyFooable(); mf.foo(); TextField textField = mf.textField; } }
------------------------ In any case, I consider it best practice to have all variables final if possible, and parameters final only if necessary (although there is an argument to having them all final). If you can't make a variable final, make sure that you couldn't just use different final variables instead of one variable repeatedly. It makes code less confusing, and there really isn't a benefit to re-using the same variable over and over, unless it is an accumulator of some sort. (sum += value, for instance)
Hope this makes sense. - Daniel.
NeoGeoSNK - 23 Nov 2006 07:23 GMT "Andreas Leitgeb 写道: "
> >>class Outer { > >> final TextField[] tf = new TextField[1]; [quoted text clipped - 18 lines] > since we're talking about local variables, that are "rarely" > (that is: never ever) shared among threads... Thanks Andreas Leitgeb And does that means a final array's elements can be modified any times? and it's unrelated with inner class?
NeoGeoSNK - 23 Nov 2006 11:39 GMT Happy Thanksgiving Day to everyone ^ ^
Andreas Leitgeb - 23 Nov 2006 12:17 GMT > And does that means a final array's elements can be modified any times? yes
> and it's unrelated with inner class? 1.) Here we're talking about inner classes in the context that they are defined inside a method.
2.) The inner class really gets a copy of all enclosing method's variables that it wants to access.
3.) because the inner class gets only a copy of them, it cannot modify the enclosing method's local variables (the originals).
4.) to prevent people from modifying the copies and then complaining that the originals remained unchanged, the originals are forced to be final, preventing any discussion about any connectivity between copy & original. If it's final, then it's trivially "connected" to the copy.
5.) It surely could have been done hundred other ways, but it wasn't :-)
That's why a local variable must be final, IF you want to access it from an inner class.
NeoGeoSNK - 24 Nov 2006 02:02 GMT "Andreas Leitgeb 写道: "
> > And does that means a final array's elements can be modified any times? > [quoted text clipped - 22 lines] > That's why a local variable must be final, IF you want to access > it from an inner class. Thanks very much Andreas Leitgeb I Think I completely understand :)
Chris Smith - 14 Nov 2006 19:52 GMT > >> it applies to all inner classes whether anonymous or not. > > Not true. Non-anonymous classes aren't declared inside a method, so have no > access to local variables, final or not. Class members don't need to be > final to be accessed from an inner class. You can declare a named local class if you like. In that case, the final restriction for local variables does apply to it. So yeah, it's true. You can, of course, also declare non-local inner classes (anonymous or otherwise) for which there are no local variables in scope, in which case this doesn't apply.
 Signature Chris Smith
Mark Rafn - 15 Nov 2006 01:28 GMT >> >> it applies to all inner classes whether anonymous or not.
>> Not true. Non-anonymous classes aren't declared inside a method, so have no >> access to local variables, final or not. Class members don't need to be >> final to be accessed from an inner class.
>You can declare a named local class if you like. In that case, the >final restriction for local variables does apply to it. I didn't know that. What's the syntax look like? If it has a class name (as opposed to just a variable name pointing to an instance of an anonymous class), can it be referenced outside of the declaring method somehow? -- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Chris Uppal - 15 Nov 2006 12:28 GMT > I didn't know that. What's the syntax look like? aMethod() { class Local extends Whatever implements WhateverElse { ... stuff ... }
Local aLocal = new Local(); ... stuff... }
> If it has a class > name (as opposed to just a variable name pointing to an instance of an > anonymous class), can it be referenced outside of the declaring method > somehow? No. What would be the point to making a class local to a method if you want to refer to it from outside the method ?
Note, named local classes (like anonymous local classes) are just syntactic sugar. Personally I prefer to use the named form, since (a) it is less restricted, and (b) it is /much/ easier to read than the terrifyingly obfuscatory define-an-entire-class-inside-the-body-of-a-new-statement syntax.
-- chris
Andreas Leitgeb - 15 Nov 2006 12:49 GMT > Note, named local classes (like anonymous local classes) are just syntactic > sugar. Personally I prefer to use the named form, since (a) it is less > restricted, and (b) it is /much/ easier to read than the terrifyingly > obfuscatory define-an-entire-class-inside-the-body-of-a-new-statement syntax. While I agree to the possibility of producing "terrifyingly obfuscated" code through anonymous classes, they are "needed" to compensate for the lack of C-like function pointers.
For someone, to whom finding appropriate names for stuff feels like the hardest part of programming, anonymous classes are just one way to remain sane.
Chris Uppal - 15 Nov 2006 13:17 GMT [me:]
> > Note, named local classes (like anonymous local classes) are just > > syntactic sugar. Personally I prefer to use the named form, since [...]
> For someone, to whom finding appropriate names for stuff feels like > the hardest part of programming, anonymous classes are just one way > to remain sane. <grin/>
Yes, I take your point, and I agree that finding good names (for anything) is hard. But, since the local classes /are/ local, there is not much hinging on the choice of name (in fact there is nothing, or the anonymous syntax wouldn't be usuable at all), so you can choose something bland like "Action" or "Handler" without making the code hard to read.
-- chris
NeoGeoSNK - 23 Nov 2006 04:44 GMT "Chris Uppal 写道: "
> > and you mean this restriction only effective when a inner class is > > anonymouse? and not for all inner class? [quoted text clipped - 6 lines] > > -- chris Thanks a lot And just as Mark Rafn says this restriction doesn't effect named inner class thant not defined in a method:)
Thomas Hawtin - 14 Nov 2006 15:12 GMT > I have two questions, why inner class can only access "final" argument > outside the inner class? Similar to Daniel's comment, it's because the implementation is easier. I believe C#2.0 takes the point of view that when you create an anonymous delegate (like an anonymous inner class only a single method and a more complicated type system) the variable should split in to - with updates from the enclosing method not interacting with the anonymous delegate code. However, the semantics of least surprise are for the local variable to remain coherent. There are proposals that Java SE 7 will allow this, possibly having to declare the local variable as "public".
> and why Java applet's init() method can't access any "final" fields? It cannot assign final fields as it is not a constructor. That being the point of final.
A better approach to organising applets (and indeed GUI code in general) is to move the bulk of the code out from subclasses of components. You can use constructors and final as you like in such code, without having to conform to AWT/Swing implementation peculiarities. You can also use the same code in JFrame, JInternalFrame, JScrollPane, etc.
Tom Hawtin
NeoGeoSNK - 23 Nov 2006 04:50 GMT "Thomas Hawtin 写道: "
> > I have two questions, why inner class can only access "final" argument > > outside the inner class? [quoted text clipped - 21 lines] > > Tom Hawtin Thanks And I think the problem is because that inner class can't access non-final local variables?and I really can't understand what does "semantics of least surprise " means :)
Mark Rafn - 14 Nov 2006 17:11 GMT >I have two questions, why inner class can only access "final" argument >outside the inner class? There is a distinction between member variables, local variables, and formal parameter variables (though the last two are darned similar).
There is also a distinction between anonymous inner classes, named inner classes, and static inner classes.
An anonymous inner class is defined inside a method, and has access to all member variables of the enclosing class, final or not (which isn't your question), and to all final variables and parameters of the method in which it's declared (which is what you're asking about). The reason they have to be final is because they're locally scoped and will disappear as soon as the method returns, which would be very bad for the anonymous class that tries to reference them later. The final modifier means it's safe for the anonymous class to keep a copy of the value when it's created, as it's guranteed not to change.
Named inner classes (those that are members of a class, not declared inside a method) have no access to any method's parameters or variables at all, so nothing needs to be declared final. It has access to member variables of the enclosing class through an implicit OuterClassName.this reference.
Named static inner classes are exactly like top-level classes (which are implicitly static). They have no access to any outside variables, except through an explicit reference just like any other class would.
>and why Java applet's init() method can't access any "final" fields? > public class AppletGui extends JApplet { [quoted text clipped - 6 lines] >encounter a compiled time error "the final field AppletGui.textvalue >can not be assigned This is unrelated to your first question. Final member variables must be assigned at class construction time (through an initializer in the declaration, an initializer block, or inside a constructor. Any attempt to assign to a final member after this is illegal. That's what final means - it can't be assigned after construction. -- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
NeoGeoSNK - 23 Nov 2006 06:23 GMT "Mark Rafn 写道: "
> >I have two questions, why inner class can only access "final" argument > >outside the inner class? [quoted text clipped - 42 lines] > -- > Mark Rafn dagon@dagon.net <http://www.dagon.net/> Thanks Mark Rafn your explain is very clear, before i see your comment, I searched many java books and couldn't find the answer^ ^.I think I can understand when I should declare a final variables or not from your answer, But I still don't don't know why the compiler must guranteed it not to change? why it is /safe/ :)
> The final modifier means it's safe for > the anonymous class to keep a copy of the value when it's created, as it's > guranteed not to change.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|