• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Why are finals allowed for method-local classes??

 
Ranch Hand
Posts: 63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In the K&B book, it said that method-local (inner) classes cannot access the method variables or args...except if they are final.
The reason it said it cannot allow access to the vars is that a reference to the inner class could be passed elsewhere, such as to the outer class, and thus when the method gets blown off the stack, references to those variables wouldn't exist once the method goes out of scope if a reference to the inner class still exists.
That's fine and makes perfect sense. But what doesn't make sense is how final variables of a method are any different....don't they also live on the stack and get blown away when the method goes out of scope?
Here's an example.

So the $65535 (0-based) question is why does it work for finals in the method?
The result, btw, is the output:
3
Ross
 
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ross Goldberg:
But what doesn't make sense is how final variables of a method are any different....don't they also live on the stack and get blown away when the method goes out of scope?


I believe final variables lives in the constant pool, not in the stack. If you think about it, the stack is use to maintain the state of one Java method invocation. And a constant is, well, a constant. Its value will remain the same for every instance of that method. So there is no need to keep it in the stack.
Just my 2 cents.
 
Ross Goldberg
Ranch Hand
Posts: 63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I tried everything I could think of to initialize the final var in the constructor (since static isn't allowed for method of the method-local class) since that would have allowed the constant to be bypassed.....but I couldn't find a method that works. For example, the one that follows complains about x being assigned in the constructor.

What you have described has some logic to it, but even so, I wasn't aware of a constants pool....just the stack(s), the heap, and the string pool. The weird thing about the above scenario is that the variable doesn't exist (presumably) until the method is entered, even though it is final. After all, why should it create something not related to the object's state if that method might never be called...let alone keep it around? After all, when the method is done, so is that variable, regardless of whether or not it is final---or so I would think. But you are indicating that the final variable, though tied to a method instance (even if the value doesn't change), is going to stick around regardless. Just doesn't seem to fit the rules...does it?
Ross
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ross Goldberg:

...The weird thing about the above scenario is that the variable doesn't exist (presumably) until the method is entered, even though it is final. After all, why should it create something not related to the object's state if that method might never be called...let alone keep it around? After all, when the method is done, so is that variable, regardless of whether or not it is final---or so I would think. But you are indicating that the final variable, though tied to a method instance (even if the value doesn't change), is going to stick around regardless. Just doesn't seem to fit the rules...does it?
Ross


When the JVM loads a class, does it defer loading the codes of the methods because some of these methods might not be called? And when the method is invoked, does it create a copy of the method instructions on the stack for every instance of this method?
I think for efficiency reason, the answer to these questions is NO. When you define a final variable and local variable, just like the code below,

the JVM has the x and y in its namespace. The difference between these 2 names is that the JVM already knows what value to associate to x. y has to wait until m() is invoked. The JVM also knows that m() can be invoked many times and possibly at the same time(thread) so y will have different values. It therefore needs to allocate a memory space for every invocation of m(). For x on the other hand, it doesn't have to create a memory space for every instance of m(). It only needs to give its fixed location.
So this is what I think. Any corrections to this thinking are most welcome.
 
Ross Goldberg
Ranch Hand
Posts: 63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Alton,
I was ready to buy into your theory when something else popped into my mind and I decided to use the outer class to keep reinitializing the constant. In this version (which compiles and runs), the final can have a different value for each instance!!
try this...
 
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There is a dirty truth here. A truth so dirty that Sun is willing to deceive you about why local variables must be final for a method-local class to access them. The truth is that method-local classes do not have access to local variables even when they are final. Local variables are in fact passed to the method-local class the same way that variables are passed to a method. So if you were allowed to make changes to the variables in the method-local class you wouldn't see the changes in the method. Sun thought this would be too confusing. Sun didn't want to worry your pretty little head about the "dirty little secret". So they tricked you. They told you the myth and then had Java pass only the final method variables to the method-local class. Why? Because now you can't make changes to those variables in the method-local class so you wouldn't be asking embarrassing questions about why your changes aren't actually changing those method variables.
Perosnally, I think programmers are a generally tough breed and we can take the truth. So don't believe the Sun myth about variables being blown off the stack. The real truth is that inner classes are a bit of a hack and Sun doesn't think you can handle the truth.
 
Ranch Hand
Posts: 34
Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,
It is true there is some "secret" mechanism occuring here. In fact, this trick is made by the java compiler.
When you compile a local inner classe, the compiler must modify or create custom Constructors. Those gets a first additional parameter which is a reference to the object that created the inner class, mainly to access all its fields within the inner class. Then, the compiler creates additional parameters to the constructors to receive all the final local variables. All those additionnal parameters are stored in private final fields inside the inner class.
This is surely a "trick". But it helps keeping the things simple for the JVM to handle inner classes.
You can see what I said by looking inside the compiled classes by the way of reflection.
Hope it helps.
 
Ross Goldberg
Ranch Hand
Posts: 63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That's pretty fascinating. It surely would have been easier if they had explained what was really going on to begin with because sooner or later, someone like me is going to question why and the answer is certainly anything but obvious!
Appreciate it.
Ross
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Thomas]: There is a dirty truth here. A truth so dirty that Sun is willing to deceive you about why local variables must be final for a method-local class to access them.
Apparently some Sun employees missed the memo about the big coverup. The original Inner Classes Specification for example said (immediately after giving the rule that local variables must be final in order to be accessible), "because of potential synchronizeation problems, there is by design no way for two objects to share access to a changeable local variable." The subsequent section on "How Inner Classes Work" makes clear that the inner class is actually being passed a copy of the local variable. Similarly, PvdL's "Just Java 2" (from Sun Microsystems Press) shows the source transformation used, and points out that the inner class has no way to affect the original local variable, so that variable is made final to avoid the possibility of different values for what is otherwise perceived to be one veriable. Other intro-level books I have lying around at the moment are Horstmann & Cornell's Core Java I, Niemeyer & Knudsen's Learning Java, and RHE. All these explicitly talk about the fact that inner classes get passed copies of local variables, and the need to keep those copies in sync with the originals (if they're still alive) is the problem for which "final" is the simplest solution. I also checked Eckel's "Thinking In Java" but didn't see any attempted explanation for why local variables must be final to be accessed from an inner class - it was just given as fact. (At least, there wasn't an incorrect explanation.) I don't have a copy of K&B (whichever one we're talking about here) but it wouldn't surprise me if there's a better explanation lurking further on in the text. So I'm not sure where this "myth about the stack" idea comes from, Tom. Was there a specific Sun source you read that promulgated it?
[Alton]: I believe final variables lives in the constant pool, not in the stack.
Incorrect. You're thinking of compile-time constants. A variable can be final without being a compile-time constant; if so, it gets created on the stack. Though it's possible some optimizations might be made, depending how/if the variable is used - but by default, it's probably still on the stack.
[ July 27, 2003: Message edited by: Jim Yingst ]
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:
So I'm not sure where this "myth about the stack" idea comes from, Tom. Was there a specific Sun source you read that promulgated it?

I had thought that my response was clearly a bit tounge in cheek. But there is a lie here. The lie is that the method variables "have" to be final. The only reason they "have" to be final is because Sun thought it would be too confusing if they weren't final. That is where my complaint is.
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jim Yingst:
[Thomas]:
[b][Alton]: I believe final variables lives in the constant pool, not in the stack.

Incorrect. You're thinking of compile-time constants. A variable can be final without being a compile-time constant; if so, it gets created on the stack. Though it's possible some optimizations might be made, depending how/if the variable is used - but by default, it's probably still on the stack.
[ July 27, 2003: Message edited by: Jim Yingst ]


Hi Jim,
Thanks for that explanation.
But I still have a question about this.
Is your statement above true for all final variables regardless how they are declared (e.g. those declared inside a method, blank final variables, initialized final variables)? Or is it true only for blank final variables? At the moment, I am assuming the latter because initialized final variables are considered compile-time constants.
 
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
final String s = args[4];
is certainly not a compile-time constant.
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I had thought that my response was clearly a bit tounge in cheek.
Sorry, such subtleties are beneath my threashold of perception sometimes. I require smilies dammit!
The lie is that the method variables "have" to be final.
Since that's clearly true from the point of view of a programmer working with the Java language as it currently exists, you're clearly talking about this from the viewpoint of language design - how else could Sun have set this up? I haven't seen this "lie" here either though. E.g. the Inner Classes Spec says "because of potential synchronizeation problems, there is by design no way for two objects to share access to a changeable local variable." "There is by design" == "to avoid this problem, we chose to implement the following design". There's no indication that they had to do it that way; it's just what they did. Similarly PvdL's book refers to forcing the variable to be final as "the simplest fix". Not necessarly the only one. Maybe some other sources imply that Sun had no choice, but I haven't seen them. And personally I agree with Sun's choice. If users want a nonfinal variable, they can explicitly make a copy, then change one to their hearts' content. Forcing the user to set up separate variables here is a Good Thing™ IMO.
In a similar vein I kinda wish they'd set things up to prevent accidental overriding, hiding, and shadowing. Maybe use a keyword to acknowledge overrides; and disallow hiding and shadowing completely. I haven't thought it all through, since it's not like I'm in a position to effect a change now anyway - but it seems to me that unwitting reuse of names is enough of a source of confusion that I'd prefer the compiler to detect it if possible. Oh well...
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

If users want a nonfinal variable, they can explicitly make a copy, then change one to their hearts' content.


Or use an array of length 1. The array variable itself has to be final, but you can change the element as much as you want within the inner class methods.
 
Ranch Hand
Posts: 787
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Ross,
I had exactly same question that you posted at the top after reading K & B:
Final implies that varible values are non-changeable rather than out living the method termination as asserted in K & B.
I understand Jim's explaination that objects created by these method-local classes can out live the method itself. Hence if they are referring to any local variables, they will have hard time finding their values after method is done. Therefore, copies of these variables are passed to these objects to take with them. But as we are making copies, now we have synchronization problem. Therefore, we have to disallow changes to these variables. Hence only finals can be seen by these objects.
But I guess I question the utility of these method local classes in first place.
If inner classes were invented to express the afinity between classes in distinct hierarchies, the instance level inner classes are doing a very good job. I percieve that they are providing a way to implement multiple inheritance. But allowing classes to be defined and instantiated in methods, assignements and arguments is bit of over-stretch and making language unneccessarily difficult. But that is one person's opinion.
Thanks
Barkat
 
Barkat Mardhani
Ranch Hand
Posts: 787
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thinking more about multiple inheritance, I guess good old composition construct can do a magnificient job:
class Child extends ApplicableGenes {
Father f;
Mother m;
}
This can inherit from both mother and father genes. The class ApplicableGenes can hold the universal truth that what genes supercedes what under what condition.
Someone will have to make a good argument for need for inner classes.
Thanks
Barkat
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Barkat Mardhani:
This can inherit from both mother and father genes. The class ApplicableGenes can hold the universal truth that what genes supercedes what under what condition.
Someone will have to make a good argument for need for inner classes.
Thanks
Barkat


The Iterators inside of Collection objects are created using an inner class. It makes sense because an Iterator that is designed specifically to work with LinkedList has no meaning outside of a LinkedList.
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Or use an array of length 1.
Right, or more generally, use any mutable reference type. Which reminds me that I also would've liked Java to have some sort of compiler-enforced "constant" keyword as well (though that would probably raise a number of complications if grafted onto the language now). Ah well...
The other consideration is that I think local classes and anonymous clases should only be used for short, simple things anyway; I hate seeing long methods. So I have no objection to Sun restricting their functionality; if programmers want to do something complex, I'd rather they were forced to make it a member class or top-level class instead. But that's my own prejudices showing I guess...
 
Ross Goldberg
Ranch Hand
Posts: 63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jim,
Remember...there is a constant keyword, "const"....it just doesn't do anything (like compile, for example!)
Thomas,
You mentioned the iterators are local classes....method-local (I presume) or nested inner?
Ron,
You said: Or use an array of length 1. The array variable itself has to be final, but you can change the element as much as you want within the inner class methods...since the reference passed in would be the same, the changes would hold and since that final reference would remain in scope after the method, other methods could access it...at least if that reference were assigned to a private variable in the outer class.
Clever! I like that. That brings up interesting implications, however (which aren't just limited to that type as Jim mentioned w/r to mutable types). For example, the final reference as you mentioned could have a value that keeps getting changed. That brings up Synch issues...particularly since the methods are the ones to be synched and if I remember correctly, the method-local class would not have access to the method itself
Jim,
As Markat mentioned, I actually read about the stack being blown off in the K&B cert book...they have been so complete and accureate in building a solid baseline of knowledge, that I saw no reason to doubt it, but the logic behind it didn't make sense to me (and know I know why).
Here is the excerpt:


Mind you, this book has literally been the greatest thing since bagel chips (which I'm thoroughly addicted to!), in conjunction with HFJ. After these books crossed my path, my learning of Java sped up significantly and thoroughly (and I plan to post a review if someone can tell me how/where...we can't post new topics in the book review section nor in the bunkhouse, so I'm not sure where we are to post OUR reviews).
Ross
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I can't vouch for every implementation of an iterator but the two I looked at were nested inner classes instantiated as an anonymous class in the iterator() method.
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Consider the following code:

When the inner class is reduced to its bytecodes:

Looking at these bytecodes, it seems that final variables are NOT pass on to the method. It is either:
1) created in the operand stack when the inner class is instantiated(lines 1 - 4),
2) obtained from the constant pool(lines 7 - 8), or
3) obtained from the heap of the enclosing class(lines 5-6).
But it also seems to me that it is OK to use non-final local variables inside the inner class provided that you don't use it as a return value. If you assign it to an instance variable of the inner class, the value just get stored in the heap. And if you return the instance variable(like in line 10), then in effect you are returning the value of the non-final local variable.
But as I said earlier, the danger is if you use the non-final local variables as a return value. Obviously there is no way for the class to refer back to it. I guess Sun just decided to make things simplier and not allow it.
Any comments on my interpretaton of the bytecodes?
[ July 28, 2003: Message edited by: Alton Hernandez ]
[ July 28, 2003: Message edited by: Alton Hernandez ]
 
Cowgirl and Author
Posts: 1589
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Howdy all,
I didn't have time to read through all of these, so forgive me if I say something you've already all said, or don't say the one thing you want to hear
Here's about the extent of internal documentation that we have...
The reason why you are not supposed to use non-final variables in a method-local inner class is because of the issue explained in our book -- the fact that the stack variable may not persist as long as the method-local inner class instance on the heap. But yes, that's the *simple* story, and obviously not the whole story. Another issue is that two different method-local objects could indeed change the value of that variable.
But... in the beta versions of Java 1.1, you actually *could* use non-final local variables in method-local inner classes. But the way it was implemented was yucky -- they had to store the value of the non-final local variable into some place in the heap.
Before final release of 1.1, they changed it to the way it is now -- which is that you are not supposed to use non-final local variables in your method-local inner class, and that the final variable must have been assigned a value *before* the inner class is defined. (So no, it does not have to be a compile-time constant).
That is ALL you need to know from the perspective of a programmer, because the rest of it is still left up to different implementations. BUT... according to Sun folks, just about everyone (if not everyone) implements it the simplest way, by making a behind-the-scenes 'secret' member variable in the inner class object which holds the value of the final variable. In other words, the value of the final local variable is assigned to a member variable of the inner class object, without your having to explicitly do that yourself. For all practical purposes, that is the way you are *supposed* to think about it. So yes, *technically* the inner class instance does not have *access* to the final variable in some bizarre, non-standard way. But that doesn't make any difference. In your code, you DO have access, and that's all that matters.
So why don't they give you a member variable with the non-final variables? Again, the main reason is because there would still be the potential for another method-local inner object to change the value out from under the other one, and it starts getting really ugly, really fast.
Bottom line: we don't *really* know exactly how a compiler might try to handle this, (disassembling with javap -c tells you what *your* compiler is doing), but virtually all of them (we think) do it by some process of giving the inner class a member variable with the value of the final local variable.
And of course, NONE of this is on the exam
(well, other than what is in the spec, which is that you are not to use a non-final local variable, and that the final variable (while it doesn't have to be a constant) must be assigned prior to the inner class definition.)
One more thing... a disclaimer. I might be completely off... but that's the way we explained it to our customers in SunEd
cheers,
Kathy
p.s. now get back to work on the stuff that IS on the exam
"If you want to learn java, dive in�Head First"
--Scott McNealy, chairman, president, CEO Sun Microsystems
 
Ross Goldberg
Ranch Hand
Posts: 63
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Kathy!!! I know I'm not *supposed* to focus on this, but it has indirectly led to a much greater understanding and reinforcement about using inner classes. However, one cannot (or at least I cannot) help but wonder why Sun decided to make the final local value assigned to the outer class...you would think there are conflicts that make that approach potentially unsafe (particularly w/r to synchronization and threads) given examples like the one Ron cited a while back about class final references/arrays) (such as final StringBuffer [] sb or final int [] sb or final StringBuffer sb)
BTW, I finished reading your cert book...plz let me know where or how I can post reviews on the two so I can give the glowing reviews they deserve.
Without re-reviewing the material (such as two-min. drills), I scored 78.5% (actually 81.5 but ran out of time with two left) on the first MasterExam. I plan to do the reviews and then take the second ME, as well as other practice exams and may go for the real thing in about a week to week and a half if there is availability (the closest center to me is about 1.5 hrs away).
Bert and you (and many ppl on this board) have been a tremendous asset to me!! Thanks!!
Ross
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

the way it was implemented was yucky -- they had to store the value of the non-final local variable into some place in the heap.


Of course, if you make your final variable an array of length 1, and treat the array as mutable, then you're doing manually what the 1.1. beta compiler was doing behind your back. Right?
 
Thomas Paul
mister krabs
Posts: 13974
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To review kathy's books:
Sun Certified Programmer & Developer for Java 2 Study Guide (Exam 310-035 & 310-027)
Head First Java
 
Kathy Sierra
Cowgirl and Author
Posts: 1589
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Man oh man Ross, you are amazing! You are in total immersion Java land now. Take a deep breath, make a few flashcards for the things you don't have nailed, and my recommendation is to try to make a few mock questions of your own to post here. I swear that's the best way to really get it settled in, and of course supports our plan to keep a steady stream of javaranchers doing all the work around here...
And don't desert us once you've passed!
(and don't forget that Bert and I already have plans for you to help us... )
cheers and thank-you so much for your good comments.
Kathy
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Kathy Sierra:
BUT... according to Sun folks, just about everyone (if not everyone) implements it the simplest way, by making a behind-the-scenes 'secret' member variable in the inner class object which holds the value of the final variable. In other words, the value of the final local variable is assigned to a member variable of the inner class object, without your having to explicitly do that yourself.



I think val$zz is the 'secret' member variable in this example (this$0 is the instance of the enclosing class).
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Alton]: Looking at these bytecodes, it seems that final variables are NOT pass on to the method.
The code you showed uses compile-time constants only. Try these:
final Integer one = new Integer(1);
final String s = args[0];
final int[] ints = new int[10];
final double rootTwo = Math.sqrt(2);
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
By the way, some languages do allow what Java prohibits: creating a "closure" function that is statically nested inside another function, can both read and write the outer function's variables, and can outlive the outer function.
Lisp and Perl both do this.
Java Glossary: Closures has a good explanation of all this.
[ July 29, 2003: Message edited by: Ron Newman ]
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


Originally posted by Jim Yingst:
The code you showed uses compile-time constants only. Try these:
final Integer one = new Integer(1);
final String s = args[0];
final int[] ints = new int[10];
final double rootTwo = Math.sqrt(2);


I tried what you suggested and it still shows that the final varibles are NOT passed to the method. But before I continue, let me qualify my understanding of 'passed to the method'. I interpret that as something similar to the this reference, which is pass to every instance method and stored at position 0 of the local variable section of the stack. I expect therefore something similar for those final variables.
So now I have this code that has 4 instance final variables that are not compile-time constants:

So looking at the codes, it seems that the local variable section of the stack only contains 2 entries. I concluded that based on the call to aload. There are only 2 types of call: the 1st one(aload_0) is obviously retrieving the reference this, the 2nd one (aload_1) is retrieving the this$0.
Now if you look at every method of the inner class, the value of the final variable is obtained from the heap(that is my understanding of what the call getfield does) of the outer class and then stored in the operand stack. So that is how I concluded that final variables are not passed to the method.
Looking at my sample codes, I start to think that the compiler would treat the final variable differently (at least in my compiler):
1. If it is a primitive compile- time constant, regardless where the final variable is declared, it is inline or hardcoded in the code.
2. If it is a String constant, then it is obtained from the constant pool
3. If it is a member variable and a reference type, regardless whether it is a initialized, it is obtained from the heap.
4. Only if it is a local variable, and NOT primitive or String compile-time constant, will it create a 'secret' member in the class to store its value.
If this is how most compiler treats final variables (which is pretty reasonable to me) then it seems that the use of the 'secret' member is more of an exception rather than the rule. This all makes sense to me. After all, why would you keep a copy when you can still access some of the final variables after the lifetime of the method?
The use of 'secret' member I think raise an important issue. The original question in this thread is "how final variables of a method are any different....don't they also live on the stack and get blown away when the method goes out of scope?" So now let me change that and ask how local final variables are any different from local instance variables... can't they be stored in a 'secret' variable so that they will not get blown away when the method is out of scope?
[ July 30, 2003: Message edited by: Alton Hernandez ]
 
Ron Newman
Ranch Hand
Posts: 1056
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To see what Jim's talking about, you need to declare those final local variables inside the method m(), not in the class Sample6a .
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ron Newman:
To see what Jim's talking about, you need to declare those final local variables inside the method m(), not in the class Sample6a .


Then what is the point of passing them to the method when it is already defined in the method?
 
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Alton the compiler will pass them to the contructor of the inner class, and they will be stored as fileds of the instance of the inner class.
 
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can you please explain this:

"because of potential synchronization problems, there is by design no way for two objects to share access to a changeable local variable."


For example, would this cause a synchronization problem, if thread-1 were executing m() and thread-2 were executing n()?

[ July 30, 2003: Message edited by: Marlene Miller ]
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Ron]: To see what Jim's talking about, you need to declare those final local variables inside the method m(), not in the class Sample6a .
Oops, yes. I spotted one problem, and completely overlooked another, which is at least as important - maybe more than the one I mentioned. Thanks, Ron.
[Alton]: Then what is the point of passing them to the method when it is already defined in the method?
The point is that this thread has been about passing method-local variables into method-local or anonymous classes. That means the variables must be declared inside a method, and then you try to use them inside an inner class which was also declared inside the same method. This is only legal if the variable is final; that's what the whole discussion has been about. Your code, instead, is taking member variables of the outer class, and trying to use them inside a named local class (defined inside a method). This is always legal; you don't even have to make the member variables final. The inner class ends up accessing those outer member viarables using the outer instance (which you correctly identified as this$0 in your code). But that's not what this thread has been about. Try:
 
Jim Yingst
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[Marlene]: Can you please explain this:
quote:
"because of potential synchronization problems, there is by design no way for two objects to share access to a changeable local variable."
For example, would this cause a synchronization problem, if thread-1 were executing m() and thread-2 were executing n()?

Yes, that would be a problem, because two threads are accessing mutable data without synchronizing (or using volatile at least). Lots of weird stuff cna happen. It's possible to imagine various ways they could have implemented solutions with built-in synchronization, but it gets complex. And inefficient. We could invoke some built-in synchonization every time a user wants to access an outer local variable, but that slows things down. And the whole nested classes idea was already meeting with a fair amount of resistance from people who found it needlessly complex already. Telling people that simple-looking anonymous classes were really hiding synchronized mutable wrapper objects for each local variable - well, that would have ben perceived as even more needless confusion. Local and anonymous classes were really originally designed for simple things (in particular, as a substitute for passing callback function references, to allow easy creation of simple event handlers and Runnables). So by banning some of the things that would lead to the creation of not-so-simple local and anonymous classes, they were really trying to limit abus of the idea. I think.
 
Marlene Miller
Ranch Hand
Posts: 1392
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you Jim. Thank you for the insights.
I am glad you mentioned the remark from the Inner Classes Specification. The Java Programming Language has a similar remark:

The only restriction is that a local variable or method parameter can be accessed only if it is declared final. The reason for this restriction relates mainly to multithreading issues and ensures that all such variables have well-defined values when accessed from the inner class.


I have always wondered what they meant. And I have always thought it curious that everyone else says with so much assurance that the reason for final variables has to do with the method returning, whereas Gosling and pals say the reason is related to multithreading issues.
 
Alton Hernandez
Ranch Hand
Posts: 443
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Jose Botella:
Alton the compiler will pass them to the contructor of the inner class, and they will be stored as fileds of the instance of the inner class.
[/CODE]


Ah yes, now I see it
[code]
class Sample6a {
void m(String args[]) {
final Integer one = new Integer(1);
final String s = args[0];
final int[] ints = new int[10];
final double rootTwo = Math.sqrt(2);
class innerM {
Integer m1(){return one;}
int [] m2(){return ints;}
double m3(){return rootTwo;}
String m4(){return s;}
}
}
}
Compiled from Sample6a.java
class Sample6a$1$innerM extends java.lang.Object {
Sample6a$1$innerM(Sample6a,java.lang.Integer,int[],double,java.lang.String);
java.lang.Integer m1();
int m2()[];
double m3();
java.lang.String m4();
}
[/code]
Thanks.
 
Why should I lose weight? They make bigger overalls. And they sure don't make overalls for tiny ads:
a bit of art, as a gift, that will fit in a stocking
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic