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...
Welcome to JavaRanch!
Thanks for the laugh about "true OO languages."
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
JFrame frame = new JFrame();
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
frame = new JFrame();
and your problem will go away!
So, the question is: do you understand why?
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.
When you say
Foo aFoo ...;
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 = 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.
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.
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!