Chapter 14
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 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.”
If you’ve read this far into Java For Dummies, 6th 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, 6th 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.
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.
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.
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:
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);
}
}
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 14-1 through 14-3 illustrate the ideas in a slightly different way.
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 14-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 14-1 displays a window like the one shown in Figure 14-4.
Listing 14-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 14-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 14-1, to make the ArtFrame
instance visible, you call the setVisible
method.
Now notice that Listing 14-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 14-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 14-2.
Listing 14-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:
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.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 14-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 14-2. In particular, the line
ArtFrame artFrame = new ArtFrame(new Drawing());
in Listing 14-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.
paint
method. This paint
method uses a standard Java trick for making things appear onscreen. The parameter g
in Listing 14-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 14-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.
The code in Listing 14-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 14-5.
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 14-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 14-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 14-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 14-3 is the word paint
. The paint
method in Listing 14-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 14-1 through 14-3, you may notice something peculiar. The paint
method in Listing 14-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 14-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 14-4.
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, 6th Edition, which has the code for these files in Listings 14-2 and 14-3!) Anyway, you want to tweak the way the oval looks in Figure 14-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 14-4.
Listing 14-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 14-4, you remember to change one of the lines in Listing 14-1. You change the line to
ArtFrame artFrame = new ArtFrame(new DrawingWide());
In Listing 14-1 you can also remove the com.burdbrain.drawings.Drawing
import declaration because you no longer need it.
Listing 14-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 14-6.
In passing, you may notice that the code in Listing 14-4 doesn’t start with a package declaration. This means that your whole collection of files comes from the following three packages:
com.burdbrain.drawings
package: The original Drawing
class from Listing 14-2 is in this package.com.burdbrain.frames
package: The ArtFrame
class from Listing 14-3 is in this 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.
If you’re reading these paragraphs in order, you know that the last example ends very happily. The code in Listing 14-4 runs like a charm. Everyone, including my wonderful editor, Brian Walls, 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 14-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 14-5.)
Listing 14-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 14-6). The DrawingWide
class is in Java’s unnamed package.
Listing 14-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 14-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.
A class’s fields and methods are called members of the class. The rules for access — default and otherwise — apply to all members of classes.
For the rundown on method-local variables, see Chapter 10.
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 14-7 and 14-8 illustrate the point.
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 14-6. The only difference is that this new DrawingWideBB
class lives inside the com.burdbrain.drawings
package. The code is shown in Listing 14-7. To run this code, I have to modify Listing 14-1 with the line
ArtFrame artFrame = new ArtFrame(new DrawingWideBB());
Listing 14-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 14-7 alongside the Drawing
class in Listing 14-5, everything works just fine. The reason? It’s because Drawing
and DrawingWideBB
are in the same package. Look back at Figure 14-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.
import com.burdbrain.drawings.DrawingWideBB;
Also, change the ArtFrame
object’s constructor call to new ArtFrame
(new DrawingWideBB())
.
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 14-8 and 14-9.
Listing 14-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 14-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 14-8 defines the Drawing
class. Listing 14-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 14-8 and 14-9. Notice the extra bit of shading in Figure 14-9. A subclass can access a protected member of a class, even if that subclass belongs to some other 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 14-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 14-10.
Listing 14-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 14-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 14-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 14-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.
Listing 14-10 has a main
method, which is inside a class, which is in turn inside the com.burdbrain.drawings
package. With most Integrated Development Environments (IDEs), you don’t think twice about running a main
method that’s in a named package. But if you run programs from the command line, you may need to type a fully qualified class name. For example, to run the code in Listing 14-10, you type java com.burdbrain.drawings.ShowFrameWideBB
.
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.
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 14-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.
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 14-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 14-7. Everything was peachy because Listing 14-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 14-3. The code in Listing 14-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 14-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.
3.15.237.123