Chapter 13
Sharing Names among the Parts of a Java Program
In This Chapter
Hiding names from other classes
Exposing names to other classes
Tweaking your code to find the right middle ground
Speaking of private fields and methods (and I do speak about these things in this chapter). . . .
I’m eating lunch with some friends of mine at work. “They can read your e-mail,” says one fellow. Another chimes in, “They know every single website that you visit. They know what products you buy, what you eat for dinner, what you wear, what you think. They even know your deepest, darkest secrets. Why, I wouldn’t be surprised if they know when you’re going to die.”
A third voice enters the fray. “It’s getting to the point where you can’t blow your nose without someone taking a record of it. I visited a website a few weeks ago, and the page wished me a Happy Birthday. How did they know it was me, and how did they remember that it was my birthday?”
“Yeah,” says the first guy. “I have a tag on my car that lets me sail through toll booths. It senses that I’m going through and puts the charge on my credit card automatically. So every month, I get a list from the company showing where I’ve been and when I was there. I’m amazed it doesn’t say who I was visiting and what I did when I got there.”
I think quietly to myself. I think about saying, “That’s just a bunch of baloney. Personally, I’d be flattered if my employer, the government, or some big company thought so much of me that they tracked my every move. I have enough trouble getting people’s attention when I really want it. And most agencies that keep logs of all my purchasing and viewing habits can’t even spell my name right when they send me junk mail. ‘Hello, this is a courtesy call for Larry Burg. Is Mr. Burg at home?’ Spying on people is really boring. I can just see the headline on the front page of The Times: ‘Author of Java For Dummies Wears His Undershirt Inside Out!’ Big deal!”
So I think for a few seconds, and then I say, “They’re out to get us. TV cameras! That’s the next big thing — TV cameras everywhere.”
Access Modifiers
If you’ve read this far into Java For Dummies, 5th Edition, you probably know one thing: Object-oriented programming is big on hiding details. Programmers who write one piece of code shouldn’t tinker with the details inside another programmer’s code. It’s not a matter of security and secrecy. It’s a matter of modularity. When you hide details, you keep the intricacies inside one piece of code from being twisted and broken by another piece of code. Your code comes in nice, discrete, manageable lumps. You keep complexity to a minimum. You make fewer mistakes. You save money. You help promote world peace.
Other chapters have plenty of examples of the use of private fields. When a field is declared private, it’s hidden from all outside meddling. This hiding enhances modularity, minimizes complexity, and so on.
Elsewhere in the annals of Java For Dummies, 5th Edition, are examples of things that are declared public. Just like a public celebrity, a field that’s declared public is left wide open. Plenty of people probably know what kind of toothpaste Elvis used, and any programmer can reference a public field, even a field that’s not named Elvis.
In Java, the words public and private are called access modifiers. No doubt you’ve seen fields and methods without access modifiers in their declarations. A method or field of this kind is said to have default access. Many examples in this book use default access without making a big fuss about it. That’s okay in some chapters, but not in this chapter. In this chapter, I describe the nitty-gritty details about default access.
And you can find out about yet another access modifier that isn’t used in any example before this chapter. (At least, I don’t remember using it in any earlier examples.) It’s the protected
access modifier. Yes, this chapter covers some of the slimy, grimy facts about protected access.
Classes, Access, and Multipart Programs
With this topic, you can become all tangled up in terminology, so you need to get some basics out of the way. (Most of the terminology that you need comes from Chapter 10, but it’s worth reviewing at the start of this chapter.) Here’s a fake piece of Java code:
class MyClass {
int myField; //a field
// (a member)
void myMethod() { //a method (another member)
int myOtherField; //a method-local variable
// (NOT a member)
}
}
The comments on the right side of the code tell the whole story. Two kinds of variables exist here — fields and method-local variables. This chapter isn’t about method-local variables. It’s about methods and fields.
Believe me, carrying around the phrase “methods and fields” wherever you go isn’t easy. It’s much better to give these things one name and be done with it. That’s why both methods and fields are called members of a class.
Members versus classes
At this point, you make an important distinction. Think about Java’s public
keyword. As you may already know from earlier chapters, you can put public
in front of a member. For example, you can write
public
static void main(String args[]) {
or
public
amountInAccount = 50.22;
These uses of the public
keyword come as no big surprise. What you may not already know is that you can put the public
keyword in front of a class. For example, you can write
public
class Drawing {
// Your code goes here
}
In Java, the public
keyword has two slightly different meanings — one meaning for members and another meaning for classes. Most of this chapter deals with the meaning of public
(and other such keywords) for members. The last part of this chapter (appropriately titled “Access Modifiers for Java Classes”) deals with the meaning for classes.
Access modifiers for members
Sure, this section is about members. But that doesn’t mean that you can ignore Java classes. Members or not, the Java class is still where all the action takes place. Each field is declared in a particular class, belongs to that class, and is a member of that class. The same is true of methods. Each method is declared in a particular class, belongs to that class, and is a member of that class. Can you use a certain member name in a particular place in your code? To begin answering the question, check whether that place is inside or outside of the member’s class:
If the member is private, only code that’s inside the member’s class can refer directly to that member’s name.
class SomeClass {
private
int myField = 10;
}
class SomeOtherClass {
public static void main(String args[]) {
SomeClass someObject = new SomeClass();
//This doesn’t work:
System.out.println(
someObject.myField
);
}
}
If the member is public, any code can refer directly to that member’s name.
class SomeClass {
public
int myField = 10;
}
class SomeOtherClass {
public static void main(String args[]) {
SomeClass someObject = new SomeClass();
//This works:
System.out.println(
someObject.myField
);
}
}
Figures 13-1 through 13-3 illustrate the ideas in a slightly different way.
Putting a drawing on a frame
To make this business about access modifiers clear, you need an example or two. In this chapter’s first example, almost everything is public. With public access, you don’t have to worry about who can use what.
The code for this first example comes in several parts. The first part, which is in Listing 13-1, displays an ArtFrame
. On the face of the ArtFrame
is a Drawing
. If all the right pieces are in place, running the code of Listing 13-1 displays a window like the one shown in Figure 13-4.
Listing 13-1: Displaying a Frame
import com.burdbrain.drawings.Drawing;
import com.burdbrain.frames.ArtFrame;
class ShowFrame {
public static void main(String args[]) {
ArtFrame artFrame = new ArtFrame(new Drawing());
artFrame.setSize(200, 100);
artFrame.setVisible(true);
}
}
The code in Listing 13-1 creates a new ArtFrame
instance. You may suspect that ArtFrame
is a subclass of a Java frame
class, and that’s certainly the case. Chapter 9 says that Java frames are, by default, invisible. So, in Listing 13-1, to make the ArtFrame
instance visible, you call the setVisible
method.
Now notice that Listing 13-1 starts with two import
declarations. The first import
declaration allows you to abbreviate the name Drawing
from the com.burdbrain.drawings
package. The second import
declaration allows you to abbreviate the name ArtFrame from com.burdbrain.frames
.
The detective in you may be thinking, “He must have written more code (code that I don’t see here) and put that code in packages that he named com.burdbrain.drawings and com.burdbrain.frames.” And, indeed, you are correct. To make Listing 13-1 work, I create something called a Drawing, and I’m putting all my drawings in the com.burdbrain.drawings
package. I also need an ArtFrame
class, and I’m putting all such classes in my com.burdbrain.frames
package.
So, really, what’s a Drawing
? Well, if you’re so anxious to know, look at Listing 13-2.
Listing 13-2: The Drawing Class
package com.burdbrain.drawings;
import java.awt.Graphics;
public
class Drawing {
public
int x = 40, y = 40, width = 40, height = 40;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
The code for the Drawing
class is pretty slim. It contains a few int
fields and a paint
method. That’s all. Well, when I create my classes, I try to keep ’em lean. Anyway, here are some notes about my Drawing
class:
At the top of the code is a package declaration. Lo and behold! I’ve made my Drawing
class belong to a package — the com.burdbrain.drawings
package. I didn’t pull this package name out of the air. The convention (handed down by the people who created Java) says that you start a package name by reversing the parts of your domain name, so I reversed burdbrain.com. Then, you add one or more descriptive names, separated by dots. I added the name drawings because I intend to put all my drawing goodies in this package.
The Drawing
class is public. A public class is vulnerable to intrusion from the outside. So in general, I avoid plastering the public
keyword in front of any old class. But in Listing 13-2, I have to declare my Drawing
class to be public. If I don’t, classes that aren’t in the com.burdbrain.drawings
package can’t use the goodies in Listing 13-2. In particular, the line
ArtFrame artFrame = new ArtFrame(new Drawing()
);
in Listing 13-1 is illegal unless the Drawing
class is public.
For more information on public and nonpublic classes, see the section entitled “Access Modifiers for Java Classes,” later in this chapter.
The code has a paint
method. This paint
method uses a standard Java trick for making things appear onscreen. The parameter g
in Listing 13-2 is called a graphics buffer. To make things appear, all you do is draw on this graphics buffer, and the buffer is eventually rendered on the computer screen.
Here’s a little more detail: In Listing 13-2, the paint
method takes a g
parameter. This g
parameter refers to an instance of the java.awt.Graphics
class. Because a Graphics
instance is a buffer, the things that you put onto this buffer are eventually displayed on the screen. Like all instances of the java.awt.Graphics
class, this buffer has several drawing methods — one of them being drawOval
. When you call drawOval
, you specify a starting position (x pixels from the left edge of the frame and y pixels from the top of the frame). You also specify an oval size by putting numbers of pixels in the width
and height
parameters. Calling the drawOval
method puts a little round thing into the Graphics
buffer. That Graphics
buffer, round thing and all, is displayed onscreen.
Directory structure
The code in Listing 13-2 belongs to the com.burdbrain.drawings
package. When you put a class into a package, you have to create a directory structure that mirrors the name of the package.
To house code that’s in the com.burdbrain.drawings
package, you have to have three directories: a com
directory, a subdirectory of com
named burdbrain
, and a subdirectory of burdbrain
named drawings
. The overall directory structure is shown in Figure 13-5.
Making a frame
This chapter’s first three listings develop one multipart example. This section has the last of three pieces in that example. This last piece isn’t crucial for the understanding of access modifiers, which is the main topic of this chapter. So, if you want to skip past the explanation of Listing 13-3, you can do so without losing the chapter’s thread. On the other hand, if you want to know more about the Java Swing
classes, read on.
Listing 13-3: The ArtFrame Class
package com.burdbrain.frames;
import java.awt.Graphics;
import javax.swing.JFrame;
import com.burdbrain.drawings.Drawing;
public
class ArtFrame extends JFrame {
private static final long serialVersionUID = 1L;
Drawing drawing;
public ArtFrame(Drawing drawing) {
this.drawing = drawing;
setTitle(“Abstract Art”);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
drawing.paint(g);
}
}
Listing 13-3 has all the gadgetry that you need for putting a drawing on a Java frame. The code uses several names from the Java API (Application Programming Interface). I explain most of these names in Chapters 9 and 10.
The only new name in Listing 13-3 is the word paint
. The paint
method in Listing 13-3 defers to another paint
method — the paint
method belonging to a Drawing
object. The ArtFrame
object creates a floating window on your computer screen. What’s drawn in that floating window depends on whatever Drawing
object was passed to the ArtFrame
constructor.
If you trace the flow of Listings 13-1 through 13-3, you may notice something peculiar. The paint
method in Listing 13-3 never seems to be called. Well, for many of Java’s window-making components, you just declare a paint
method and let the method sit there quietly in the code. When the program runs, the computer calls the paint
method automatically.
That’s what happens with javax.swing.JFrame
objects. In Listing 13-3, the frame’s paint
method is called from behind the scenes. Then, the frame’s paint
method calls the Drawing
object’s paint
method, which in turn, draws an oval on the frame. That’s how you get the stuff you see in Figure 13-4.
Sneaking Away from the Original Code
Your preferred software vendor, Burd Brain Consulting, has sold you two files — Drawing.class
and ArtFrame.class
. As a customer, you can’t see the code inside the files Drawing.java
and ArtFrame.java
. So, you have to live with whatever happens to be inside these two files. (If only you’d purchased a copy of Java For Dummies, 5th Edition, which has the code for these files in Listings 13-2 and 13-3!) Anyway, you want to tweak the way the oval looks in Figure 13-4 so that it’s a bit wider. To do this, you create a subclass of the Drawing
class — DrawingWide
— and put it in Listing 13-4.
Listing 13-4: A Subclass of the Drawing Class
import java.awt.Graphics;
import com.burdbrain.drawings.Drawing;
public class DrawingWide
extends Drawing
{
int width = 100, height = 30;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
To make use of the code in Listing 13-4, you remember to change one of the lines in Listing 13-1. You change the line to
ArtFrame artFrame = new ArtFrame(new
DrawingWide
());
In Listing 13-1 you can also remove the com.burdbrain.drawings.Drawing
import declaration because you no longer need it.
Listing 13-4 defines a subclass of the original Drawing
class. In that subclass, you override the original class’s width and height fields and the original class’s paint
method. The frame that you get is shown in Figure 13-6.
In passing, you may notice that the code in Listing 13-4 doesn’t start with a package declaration. This means that your whole collection of files comes from the following three packages:
The com.burdbrain.drawings
package. The original Drawing
class from Listing 13-2 is in this package.
The com.burdbrain.frames
package. The ArtFrame
class from Listing 13-3 is in this package.
An ever-present, unnamed package. In Java, when you don’t start a file with a package declaration, all the code in that file goes into one big, unnamed package. Listings 13-1 and 13-4 are in the same unnamed package. In fact, most of the listings from the first 12 chapters of this book are in Java’s unnamed package.
At this point, your project has two drawing classes — the original Drawing
class and your new DrawingWide
class. Similar as these classes may be, they live in two separate packages. That’s not surprising. The Drawing
class, developed by your friends at Burd Brain Consulting, lives in a package whose name starts with com.burdbrain. But you developed DrawingWide
on your own, so you shouldn’t put it in a com.burdbrain
package.
The most sensible thing to do is to put it in one of your own packages, such as com.myhomedomain.drawings
; but putting your class in the unnamed package will do for now.
One way or another, your DrawingWide
subclass compiles and runs as planned. You go home, beaming with the confidence of having written useful, working code.
Default access
If you’re reading these paragraphs in order, you know that the last example ends very happily. The code in Listing 13-4 runs like a charm. Everyone, including my wonderful editor, Paul Levesque, is happy.
But, wait! Do you ever wonder what life would be like if you hadn’t chosen that particular career, dated that certain someone, or read that certain For Dummies book? In this section, I roll back the clock a bit to show you what would have happened if one word had been omitted from the code in Listing 13-2.
Dealing with different versions of a program can give you vertigo, so I start this discussion by describing what you have. First, you have a Drawing
class. In this class, the fields aren’t declared to be public and have the default access. The Drawing
class lives in the com.burdbrain.drawings
package. (See Listing 13-5.)
Listing 13-5: Fields with Default Access
package com.burdbrain.drawings;
import java.awt.Graphics;
public
class Drawing {
int x = 40, y = 40, width = 40, height = 40;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
Next, you have a DrawingWide
subclass (copied, for your convenience, in Listing 13-6). The DrawingWide
class is in Java’s unnamed package.
Listing 13-6: A Failed Attempt to Create a Subclass
import com.burdbrain.drawings.*;
import java.awt.Graphics;
public class DrawingWide
extends Drawing
{
int width = 100, height = 30;
public void paint(Graphics g) {
g.drawOval(
x
, y
, width, height);
}
}
The trouble is that the whole thing falls apart at the seams. The code in Listing 13-6 doesn’t compile. Instead, you get the following error messages:
x is not public in com.burdbrain.drawings.Drawing;
cannot be accessed from outside package
y is not public in com.burdbrain.drawings.Drawing;
cannot be accessed from outside package
The code doesn’t compile, because a field that has default access can’t be directly referenced outside its package — not even by a subclass of the class containing the field. The same holds true for any methods that have default access.
In Java, the default access for a member of a class is package-wide access. A member declared without the word public, private, or protected in front of it is accessible in the package in which its class resides. Figures 13-7 and 13-8 illustrate the point.
Crawling back into the package
I love getting things in the mail. At worst, it’s junk mail that I can throw right into the trash. At best, it’s something I can use, a new toy, or something somebody sent especially for me.
Well, today is my lucky day. Somebody from Burd Brain Consulting sent a subclass of the Drawing
class. It’s essentially the same as the code in Listing 13-6. The only difference is that this new DrawingWideBB
class lives inside the com.burdbrain.drawings
package. The code is shown in Listing 13-7. To run this code, I have to modify Listing 13-1 with the line
ArtFrame artFrame = new ArtFrame(new
DrawingWideBB
());
Listing 13-7: Yes, Virginia, This Is a Subclass
package com.burdbrain.drawings;
import java.awt.Graphics;
public class DrawingWideBB extends Drawing {
int width = 100, height = 30;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
When you run Listing 13-7 alongside the Drawing
class in Listing 13-5, everything works just fine. The reason? It’s because Drawing
and DrawingWideBB
are in the same package. Look back at Figure 13-8 and notice the shaded region that spans across an entire package. The code in the DrawingWideBB
class has every right to use the x
and y
fields, which are defined with default access in the Drawing
class, because Drawing
and DrawingWideBB
are in the same package.
Protected Access
When I was first getting to know Java, I thought the word protected meant nice and secure, or something like that. “Wow, that field is protected. It must be hard to get at.” Well, this notion turned out to be wrong. In Java, a member that’s protected is less hidden, less secure, and easier to use than one that has default access. The concept is rather strange.
Think of protected access this way. You start with a field that has default access (a field without the word public, private, or protected in its declaration). That field can be accessed only inside the package in which it lives. Now add the word protected to the front of the field’s declaration. Suddenly, classes outside that field’s package have some access to the field. You can now reference the field from a subclass (of the class in which the field is declared). You can also reference the field from a sub-subclass, a sub-sub-subclass, and so on. Any descendent class will do. For an example, see Listings 13-8 and 13-9.
Listing 13-8: Protected Fields
package com.burdbrain.drawings;
import java.awt.Graphics;
public class
Drawing
{
protected
int x = 40, y = 40, width = 40, height = 40;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
Listing 13-9: The Subclass from the Blue Lagoon, Part II
import java.awt.Graphics;
import com.burdbrain.drawings.Drawing;
public class DrawingWide
extends Drawing
{
int width = 100, height = 30;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
Listing 13-8 defines the Drawing
class. Listing 13-9 defines DrawingWide
, which is a subclass of the Drawing
class.
In the Drawing
class, the x
, y
, width
, and height
fields are protected. The DrawingWide
class has its own width
and height
fields, but DrawingWide
references the x
and y
fields that are defined in the parent Drawing
class. That’s okay even though DrawingWide
isn’t in the same package as its parent Drawing
class. (The Drawing
class is in the com.burdbrain.drawings
package; the DrawingWide
class is in Java’s great, unnamed package.) It’s okay because the x
and y
fields are protected in the Drawing
class.
Compare Figures 13-8 and 13-9. Notice the extra bit of shading in Figure 13-9. A subclass can access a protected member of a class, even if that subclass belongs to some other package.
Putting non-subclasses in the same package
Those people from Burd Brain Consulting are sending you one piece of software after another. This time, they’ve sent an alternative to the ShowFrame
class — the class in Listing 13-1. This new ShowFrameWideBB
class displays a wider oval (how exciting!), but it does this without creating a subclass of the old Drawing
class. Instead, the new ShowFrameWideBB
code creates a Drawing
instance and then changes the value of the instance’s width
and height
fields. The code is shown in Listing 13-10.
Listing 13-10: Drawing a Wider Oval
package com.burdbrain.drawings;
import com.burdbrain.frames.ArtFrame;
class ShowFrameWideBB {
public static void main(String args[]) {
Drawing drawing = new Drawing();
drawing.width = 100;
drawing.height = 30;
ArtFrame artFrame = new ArtFrame(drawing);
artFrame.setSize(200, 100);
artFrame.setVisible(true);
}
}
So, here’s the story. This ShowFrameWideBB
class in Listing 13-10 is in the same package as the Drawing
class (the com.burdbrain.drawings
package). But ShowFrameWideBB
isn’t a subclass of the Drawing
class.
Now imagine compiling ShowFrameWideBB
with the Drawing
class that’s shown in Listing 13-8 — the class with all those protected fields. What happens? Well, everything goes smoothly because a protected member is available in two (somewhat unrelated) places. Look again at Figure 13-9. A protected member is available to subclasses outside the package, but the member is also available to code (subclasses or not) within the member’s package.
Access Modifiers for Java Classes
Maybe the things that you read about access modifiers for members make you a tad dizzy. After all, member access in Java is a very complicated subject with lots of plot twists and cliffhangers. Well, the dizziness is over. Compared with the saga for fields and methods, the access story for classes is rather simple.
A class can be either public or nonpublic. If you see something like
public class Drawing
you’re looking at the declaration of a public class. But, if you see plain old
class ShowFrame
the class that’s being declared isn’t public.
Public classes
If a class is public, you can refer to the class from anywhere in your code. Of course, some restrictions apply. You must obey all the rules in this chapter’s “Directory structure” section. You must also refer to a packaged class properly. For example, in Listing 13-1, you can write
import com.burdbrain.drawings.Drawing;
import com.burdbrain.frames.ArtFrame;
...
ArtFrame artFrame = new ArtFrame(new Drawing());
or you can do without the import declarations and write
com.burdbrain.frames.ArtFrame artFrame =
new com.burdbrain.frames.ArtFrame
(new com.burdbrain.drawings.Drawing());
One way or another, your code must acknowledge that the ArtFrame
and Drawing
classes are in named packages.
Nonpublic classes
If a class isn’t public, you can refer to the class only from code within the class’s package.
I tried it. First, I went back to Listing 13-2 and deleted the word public. I turned public class Drawing
into plain old class Drawing
, like this:
package com.burdbrain.drawings;
import java.awt.Graphics;
class Drawing
{
public int x = 40, y = 40, width = 40, height = 40;
public void paint(Graphics g) {
g.drawOval(x, y, width, height);
}
}
Then I compiled the code in Listing 13-7. Everything was peachy because Listing 13-7 contains the following lines:
package com.burdbrain.drawings;
public class DrawingWideBB extends Drawing
Because both pieces of code are in the same com.burdbrain.drawings
package, access from DrawingWideBB
back to the nonpublic Drawing
class was no problem at all.
But then I tried to compile the code in Listing 13-3. The code in Listing 13-3 begins with
package com.burdbrain.frames;
That code isn’t in the com.burdbrain.drawings
package. So when the computer reached the line
Drawing drawing;
from Listing 13-3, the computer went poof! To be more precise, the computer displayed this message:
com.burdbrain.drawings.Drawing is not public
in com.burdbrain.drawings;
cannot be accessed from outside package
Well, I guess I got what was coming to me.