Assuming you did the last exercise, you have seen that some classes won’t work properly if you change their fields directly instead of going through their methods. In this exercise, you’ll learn how to put a stop to that.
You’ll also learn about something that’ll make it easier for others to use your classes and make it safer, too.
This is basically SphereCalc2, just shrunk down. When all you’re doing in a method is returning the value of a single variable, Java programmers often write the “getter” methods all on one line like I did in lines 10-12.
So the only interesting change is at the beginning of line 2: the keyword
private
.
You’ve been making things public
since your first Java program ever thanks
to “public static void main”, so maybe you suspected.
Instance variables are typically made private. Almost always, as a matter of fact. (You can designate methods as private instead of public, too, but we won’t see an example of that for a while.)
Private means “DON’T TOUCH!” Any private variable can’t be accessed in any way outside of the class where it is defined.
Inside the class, private variables work just like the fields we have been using; any method inside the class is free to change or access private variables just the same.
“Public” and “private” are called “access level modifiers” in Java. When you leave them out (like we’ve been doing with our fields since exercise 4) the default access is called “package-private”, which means that they’re accessible to anything inside the same “package”. All the classes we’ve written so far are all inside the same package, but we won’t do anything about that until close to the end of the book.
So for our purposes, “public” variables and variables with no package modifier are equivalent: they can be accessed or changed from outside their class. And that’s a bad thing.
Java programmers are typically pretty strict about making fields private. In fact, on the Advanced Placement Computer Science exam, failing to mark an instance variable as private is so serious that it can cost you more than 10% of your score on a question, even if every other part of your solution is perfect!
Anyway, back to the main point. Now that the fields are private, code that uses
the SphereCalc3
class has no choice; they can only change the radius
through the setRadius()
method. Attempts to do it directly won’t even
compile.
As you can see, this applies even if you’re not trying to change the instance
variable. private
doesn’t just prevent modifying the field, it prevents
accessing it, too. That’s why you have to write public “getter” methods for
every variable you want accessible.
Some programming languages (like C#) have a slightly different way of dealing with this problem; you can mark variables as read-only so they can’t be changed from outside the class (only through methods) but they can still be read. Other languages have a way of making it look like you’re accessing a variable directly, but they’re really secretly running a method to set or read the variable.
In Java, however, private fields with setters and getters are the only good solution.
Now, one more potential problem before we move on. It is a little bit annoying to have to always remember to call the setter method before doing anything else. Look at some examples from the past several exercises:
Not only is this annoying, it’s not safe. I won’t make you do it in
the Study Drills, but if you accidentally forgot to call setNumber()
or setValues()
the driver would still compile, but it wouldn’t work
properly. And as much as I hate compile-time errors, I hate it a lot
more when I have code that compiles but doesn’t work.
Fortunately, there’s a solution! A special sort-of setter method called a “constructor”. Here’s an example.
Lines 4 through 8 are the implementation of the constructor. Notice on line
4 that unlike the setRadius()
setter/mutator method, the constructor
is not void
. Constructors have no return type specifier at all;
it’s just missing.
Also notice that the constructor has the same name as the class itself. This is required. If you do those two things, then instead of having to remember to call some special method to pass in initial values for the instance variables, you get to pass them in while you’re instantiating the object. Which you would have to do anyway! Like so:
This makes a little more work when implementing a class, because you usually have to write a constructor and also write your setter methods. But it makes it easier to work with your object and safer, too.
Okay, that’s enough for now. We’ll see plenty more constructors in the chapters to come.
“Learn Object-Oriented Java the Hard Way” is ©2015–2016 Graham Mitchell