|
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
New topics:
So far, all the methods we've written could be asked of any object: if we made ten different PizzaServers, we could ask any of them pizzaArea(20) and always get the same answer. (Likewise for EmCees, EBayExperts, etc.) Which means it's rather odd to even have the notion of several different PizzaServer objects: we can't do anything with five PizzaServers which we couldn't do with just one.
However, if you've been paying close attention, we have seen a case where different objects, when asked the same question, can give different answers:
String firstName = "Ian"; // Declare *and* initialize a local var, together. String lastName = "Barland"; firstName.substring(0,1) // Will return "I". lastName.substring(0,1) // Will return "B". |
In addition to being area-calculating-wizards, another important facet of being a PizzaServer is having a salary. We want to say that new PizzaServers start at minimum wage, (although their salary might be set to be higher later on).
class PizzaServer { // Named constants omitted... double salary = 5.75; // Salary, in $/hr. // Code for methods omitted... } |
Okay, great — now every PizzaServer has a salary (in addition to being able to be asked a bunch of area-calculation questions). If we make twenty PizzaServers, we'll still have twenty objects which all look the same — they all make minimum wage. It turns out, we can make a method which modifies a PizzaServer's salary:
/** Set this PizzaServer's salary. * @param newSalary the new salary for this PizzaServer (in $/hr). */ void setSalary( double newSalary ) { this.salary = newSalary; // Overwrite the field's old value with a new one. } |
Let's make a two PizzaServers, called (say) jo and mo, bring up inspector windows for both of them, and then call jo.setSalary(6.50);. (Note that in the Code Pad, we need to include the semicolon here, because there is no answer coming back from setSalary; it is simply doing something.) We see that jo's salary indeed changes, while mo's salary stays the same. What if we make a new, third PizzaServer — what do you think their salary will be? Why?
setSalary is called a setter method for the field salary.
Edict of programming: Edict of programming: For each field, have a setter and getter method (as appropriate).
The purpose of setSalary is different from any function we've seen before: it's duty is not to return an answer, but instead to change a PizzaServer's state. There are three new things to notice:
Note: the documentation for a getter and setter are fairly rote:
/** Return this Floobar's numHooshaloomps. * @return this Floobar's numHooshaloomps. */ int getNumHooshaloomps() { } /** Set this Floobar's numHooshaloomps. * @param newNumH The new value for this Floobar's numHooshaloomps. */ setNumHooshaloomps( ) { . = ; } |
Our new syntax:
class-declaration ::=
class nameClass {
field-declarations...
method-declarations...
}
|
field-declaration ::=
type namefield = expression;
|
Practice
Suppose that in addition to having a salary,
PizzaServers also get their paycheck put into a bank account.
With a partner, add a field balance, which is initialized to 0.
Write setBalance, a setter method for that field.
Note that later, we'll write methods for actually paying a
PizzaServer depending on how many hours they've worked;
right now we simply write the setter method which we'll use in the future.
When to use a field, and when to use a local variable?
Only use a field to represent state which belongs to the object.
For instance, a PizzaServer's salary or bank balance or whether they're a manager
or their hair color (if such things matter to your program).
Do not use fields just so you can have a variable which
spans two methods.
For instance, don't make diam a field of PizzaServer,
just because you want crustArea to not have to bother
passing an input to pizzaArea.
If you need to use a value from one method in another method,
use parameters to pass that value in.
A technicality: We could declare a local variable on one line, and then initialize it on the next line. However, Java doesn't allow us to do that with fields — you can't have a line of (initialization) code which isn't inside some method. Tomorrow, we'll see constructor methods — special method for initializing fields5. This technicality isn't anything inherent, it's just a good practice which Java decided to enforce. Conceivably other object-oriented languages could allow initialization statements (using if, for example) to follow the class definition, outside of any method.
We've seen how to use BlueJ's Inspect option on objects, so that we can see the state of an object. But how can you do this from inside your program? We'll make getter methods, for any information which the object is willing to share with people who ask it:
/** A getter for salary. * @return this PizzaServer's salary, in $/hr. */ double getSalary() { return this.salary; } |
Note that most code will call the getter and a setter for a field, rather than access it directly. After all, it's a bit rude, to reach into a PizzaServer directly and look at or change their salary; instead it's polite to ask them what their salary is. The only functions which will refer directly to a field are, the getter, the setter, and sometimes constructors (a type of method which we'll talk about later this week, whose job is to initialize all fields). Issues of politeness aside, can you give some reasons why it's a good software practice, to always use getters and setters? (Hint: What future changes might be made, which would require only one change to the code if getters/setters are used, and many changes if other code was accessing/changing the field willy-nilly?)
Practice: Write a method
/** Calculate how much would this PizzaServer earn this week, for a given number of hours? * @param proposedHours A number of weekly hours of work being considered. * @return how much would this PizzaServer earn, if they worked for proposedHours? (In $.) * Note: this does not change the PizzaServer's state. */ |
1 I wish and that it would draw dashed lines from the window to the bench, to show this connection. Alas, windowing systems don't really let you draw something that's not inside one window. Still, at least BlueJ could border the inspector window red. ↩
2And, all other fields are unchanged, and all other objects have not changed their state. Whew! Specifying correctness suddenly is much more involved, than when we just had nice, self-contained functions! ↩
3It's a technical Java distinction: Anything with a semicolon is a statement, not an expression. So:
4 Other programming languages, striving to be more uniform, do have a void-value which isn't a useful datum, but does allow every function to always return something. ↩
5 So in Java, if you declare a field, you must either
home—info—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
©2008, Ian Barland, Radford University Last modified 2008.Feb.13 (Wed) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |