This is my first posting to javaranch, though I have been learning a lot over the past few weeks just from reading the responses to various questions--so thanks to everybody for asking and answering questions!
I'm working with the Head First Java book. I've taken one of the code examples given there and have been slightly tweaking it (helps me learn stuff),and I've run into a problem that I think shows that I don't understand something fairly fundamental.
Here's the code. Basically, it just creates a panel, a text box within the panel, and a button to press. Originally, the code was such that when the button was pressed,the text box printed 'button clicked' for every time it was pressed. I thought I'd just see if I could change it a bit so that after 5 times of pressing, it would print 'Knock it off' and after 10 times it would print 'That's it, I quit' and then close the panel (or make it invisible).
It compiles just fine, and runs fine until I press the button 10 times, at which time it prints out "That's it, I quit!"...and then I get a series of exception errors:
Obviously there is an unknown source problem. Heh. I'm guessing my problem involves the code in bold.
My guess is that I'm doing something wrong regarding using 'frame', but I'm not sure what...and I'm still not the clearest on public/private variables just yet.
I'm almost certain that I'm missing something simple and basic (and therefore important) here, so I'd appreciate a nudge in the right direction.
I realize that this is a 'homework-ish' type problem, but it would help me to understand better in general, so thanks in advance.
ps--oh, and could somebody tell me if Java is a TRUE object-oriented language? Just kidding...
Let's see. In your event handler, you've got a line commented out "int x = 0;" Now, I think that means you did declare "x" as a local variable at first, found that didn't work, and then moved it to be a member variable, and it worked. Right?
I bring this up because your problem is due to something similar. There are two frame variables here: one a member, and one local to the method "go", which contains the line
that means the member stays "null", always, and so when the action listener tries to use it, it will be null, and you get this exception. What you want to do is have "go" use the member variable, not a local. Change that one line to
i was about to make my post to help jeff, but you managed to beat me to it.
don't you have a JOB or something?
Of course, your answer is better than mine would have been. i'll just have to get faster...
There are only two hard things in computer science: cache invalidation, naming things, and off-by-one errors
Joined: Jul 20, 2005
Thanks for your help (both of you!).
The answer to your question about whether or not I understand why is: Yes and No. Heh.
I have an intuition about it--for instance, my event handler DOES use 'text' just fine, so I figured that the way text was set in go() (text = new JText) is fundamentally different from the way frame was set in go() (JFrame frame = new JFrame).
But I really don't understand the purposes/reasons for declaring variables in the two different ways.
First of all, why, in the original code given in the book, would one want to declare frame with 'JFrame frame = new JFrame'? That is, what reason would you want to declare it that way, rather than 'frame = new JFrame'?
Secondly, 'JFrame frame = new JFrame' is setting frame as a member variable, right? And 'frame = new JFrame' is setting frame as a local variable, right? Or do I have that backwards? It's still a bit confusing, obviously.
Thanks again for the help. I recognize that some of this is just conceptual stuff that I may have to just sort out on my own, but your help is most appreciated.
author and iconoclast
you're declaring a variable. Where this code appears is important, as it determines the scope of the variable. If this is in the body of the class, then you make a member variable. If it's in the body of a method, then you've made a member variable. Most important for you: if it's in both, then you declare two variables, one of each; the local will be used in the method where it's declared, and the member will be used everywhere else. The local is said to "hide" or "shadow" the member -- and this is almost always an accident and a bug.
Now, what the "..." is determines what initial value, if any, gets assigned to the variable; and where it happens determines when the assignment gets done. Although you can write
Foo foo = new Foo();
all on one line, you can also write
Foo foo; foo = new Foo();
(in some places, anyway) and it's really perfectly equivalent. The tricky part, perhaps, is when you declare a variable in one place, and initialize it -- assign a value to it -- later, like this:
One simple rule of thumb is that variables used only in one invocation of one method should be local, and variables shared by multiple methods or invocations should be members. In your program, "x" is shared by multiple method invocations, and "frame" is shared by multiple methods, so both ought to be members. But, for example "button" and "scroller" in go() should be locals, as they're never used outside of their defining method.
Joined: Jul 20, 2005
Thanks again Ernest for your help. It is definitely getting clearer. I see now that in the original program, 'frame' was declared and initialized within go(), making it a local variable--and this was done because originally, 'frame' was only to be used within go(). It was my meddling with things, and trying to use 'frame' from within another method that led to the trouble. Because I wanted to use 'frame' in a method outside of go(), I need to make sure that frame is declared as a memeber--that is, I have to declare it in the body of the class, rather than only in the body of the go() method.
Now my question is: Why not declare everything as a member? I'm guessing the answer is that it can create possible problems later on, make for messy code and the like, but is there a more specific reason not to?
Also, just to be clear, you wrote:
If this is in the body of the class, then you make a member variable. If it's in the body of a method, then you've made a member variable.
I'm hoping/guessing that there is a slight typo here, and you meant to say:
If this is in the body of the class, then you make a member variable. If it's in the body of a method, then you've made a local variable.
...otherwise I'm still not getting something important!
Thanks once again for your help. And so quickly, too. Hopefully someday I can help somebody out in a similar way.
author and iconoclast
Why not make everything a member? Well, lots of reasons. A few off the top of my head:
- There are plenty of variables (loop counters, pointers to open files) which are meaningful only during the method where they're used. Sharing them between methods simply wouldn't work -- or would be terribly confusing. Saving something in a member implies that it will be useful after the method returns; if it's not, that makes it harder to understand your rationale.
- If methods communicate via members rather than, say, via method parameters, then that communication is "hidden". It's harder to understand the code. Worse, one method can change a member variable and inadvertently change the operation of some other method that uses it. Therefore, it's best to limit use of member variables to a few well-understood cases.
- If you have a class Person, and you have, say, 100,000 Person objects in your program (it's a payroll program, say) then every 4-byte member variable adds a half a megabyte to your memory requirements.
There are more!
Joined: Jul 20, 2005
That all makes sense.
Thanks again for all of your help; I understand all of this a lot better than I did at the beginning of the day!
Maybe someday I'll understand enough to even grasp what your book is about, Ernest!