The very first Java word you typed was "public." We haven't talked very much about what that really means, though. In the reading on Methods, you saw this demonstration of method signature:
![]() public |
|
As you can see, the keyword public signifies the access level of this method. Public access is the most open--anybody with an object of type String will be able to call the endsWith() method from any Java program. Class String probably has plenty of other methods that are not public, but you won't see them listed in the API Specification. The whole idea is to hide them from you, the client programmer. Only the person who actually wrote class String needs to know about those other methods. When those methods were written, the access level was restricted like this:
![]() private |
|
Using the keyword "private" ensures that the method can be called only inside of the definition of class String. This would be used for methods that we're not even aware of as we use class String. The methods are internal to the working of the class; they help the public methods do what they need to do. If there were some procedure that several different public methods all had in common, that common procedure could be written into a private method that can then be called as needed. For example, you can see that class String has a bunch of valueOf() methods which turn various kinds of numerical primitives into strings. Turning an int into a string probably requires a very similar procedure to turning a long into string, so perhaps some part of that process is shared in a private method.
What's the advantage of keeping part of the class secret? First, it makes it easier for us to read the API Specification if it only includes the methods that we will want to use. It would be confusing if we had to wade through a long list of things that don't concern us. Second, and more important, the people who write the internal workings of the class would like to have the option to change that in the future. With access control, their only obligation is to maintain the public methods listed in the API Spec. We want our old Java programs to continue to work; those public methods need to still be there, with the same signature. However, it doesn't matter to us how those methods accomplish their task. Private methods can be changed, removed, combined, renamed--it won't bother us a bit. Blocking us from the internal workings of a class is known as "implementation hiding." If you think of a class as consisting of both an interface and an implementation, the API Specification shows us only the interface: a list of method signatures.
Fields can also be hidden. In fact, fields are rarely public. Look at class Component, for example. The API Specification lists a few static fields available for alignment, but that's it. Now we know full well that a component would have tons of information that needs storing. The component has a color, a size, a location, a font, and so on. That information has to be remembered somewhere, or the component could never be redrawn when the screen is refreshed. They're hiding it from us and here's how they did it:
public abstract class Component{
private Color background;
private Color foreground;
private Font font;
private int width;
private int height;
...
}
Well, since they're hiding it from us, I don't know if they did it exactly like that, but it was something like that. Here is a little experiment I did to catch it in the act:
import java.awt.*;
public class Nosy{
public void askQuestions(){
Button myButton = new Button();
System.out.println(myButton.favoriteIceCream);
System.out.println(myButton.x);
}
}
}
I got two compile-time errors. The first was our trusty old "cannot resolve symbol" telling me that myButton does not have a field called favoriteIceCream. The second error was for myButton.x-- but it did not say "cannot resolve symbol." Oh it recognized that symbol, alright. It knows full well that myButton has a field called x. But here's what it said to me:
x is not public in java.awt.Component; cannot be accessed from outside package
Aha! it admits that it has an x! I tried the same thing with myButton.font, myButton.height and a few other things. I got the same message. Those fields are definitely in there. I suppose I shouldn't complain so much. We can in fact get access to those fields, but we have to do it indirectly through methods, such as getFont(), getX, getWidth() and so forth. This is a very common practice-- keep the fields private, but allow access through methods. In fact those methods are even called "accessor methods." There are also methods known as "modifier methods" which will allow you to change the value of a field. Modifier methods generally start with the word "set." So class Component might have been written something like this:
public abstract class Component{
private Color background;
private Color foreground;
private Font font;
private int width;
private int height;
...
public Color getBackground(){
return background;
}
public void setBackground(Color c){
background = c;
}
...
}
As you can see, the methods are public while the fields are private. The body of the get and set methods is very simple. You should start using the same practice when you write your own classes. Let's take a look back at class Pawn and see if private fields make sense there:
public class Pawn extends ChessPiece{
private boolean firstMove = true;
//class constructor
public Pawn(int originalRow, int originalColumn){
...
}
public void moveTo(int newRow, int newColumn){
...
}
public boolean moveIsLegal(int originalRow, originalColumn){
...
}
}
Do we need get and set methods for the private field of firstMove? I don't think so. The value of firstMove only matters in determining if a proposed move is legal. That determination is made right here within the class, so the firstMove field can be kept completely private. Anybody else designing a chess applet and wanting to use our pieces only needs access to the moveIsLegal method. They'll never even know we have that private field!
Now let's consider private fields for our superclass ChessPiece:
public abstract class ChessPiece{
private String pieceName;
private int row;
private int column;
...
public int getRow(){
return row;
}
public void setRow(int n){
row = n;
}
...
}
This will compile just fine, but when you try to compile class Pawn, you get multiple errors looking like this:
column has private access in ChessPiece
Class Pawn needs access to the value of column, so it can determine if a move is legal or not. One would think that if class Pawn is a subclass of ChessPiece it ought to have some special privileges. It can't even know its own column value? That seems ridiculous. There is a solution--it's known as "protected" access:
![]() protected |
|
Protected access is not as restrictive as private access, but not as open as public access. It allows subclasses to get at the fields. Use private access only when you have no subclasses. It's fine for class Pawn, since there are no subclasses of that.
Come to think of it, class Component has plenty of subclasses, so it couldn't have made its fields private either. In fact, class Component is abstract--which means it would be idiotic to make the fields private. Abstract classes don't get used until somebody makes a subclass of them. If the fields were private, they would never see the light of day.
Remember also that we got this error message when we tried to make ChessPiece's fields private:
column has private access in ChessPiece
while we got a different error message when we tried to tap into class Components fields:
x is not public in java.awt.Component; cannot be accessed from outside package
Does that mean that class Component has protected fields? Would we be able to get at them if we made a subclass of Component? I don't know why I'm so determined to get access to those fields. I guess it makes me feel excluded that they're sitting there and I'm not allowed to manipulate them. Or maybe I just get a little sense of glee from the idea that I could outsmart a system designed to exclude me. If you remember, class ChessSquare is a subclass of class Panel and ultimately a subclass of class Component. So maybe we can access some of Component's fields from within class ChessSquare. But I tried it and still got the same error message as above. Rats, foiled again.
So what access level do those fields have? We know they're not public. They can't be private either, because the error message would have said so. And if they were protected, our subclass would have been able to get to them. What else is there?? There is actually one other type of access. It doesn't have its own keyword, like public, private and protected do. It's the default access level, the one you get by not saying anything in front of the field or method declaration.
Default access is sometimes called "friendly access" or "package access." In strictness, it's in between private and protected. It will allow access to all classes within the same package. A package is a group of classes. Class Component is a member of the package known as "awt." You've seen that name when you import classes. The awt package also includes class Button, class Label--lots of things that are related to the graphical user interface. (It stands for "abstract windowing toolkit.") So every class in the awt package will be able to get class Component's fields. Our ChessSquare class, however, is not a member of that package and that's why we are blocked from the fields. Protected access is wider, because it allows access to all classes in the package, as well as to any subclass not in the package.
Okay, I give up on getting direct access to class Component's fields. To do so, my class would have to be a member of the awt package, but that's not possible. Sun put together that package and we can't alter what's in it.
We can, however, make our own little exclusive club that other people can't get in. (I seem to be having a hard time shaking that junior high mentality.) When you are writing your programs and saving them in your h:\java directory, you actually have a package there even though you don't know it. The compiler creates a default package if you don't specify one. Everything in that directory would be part of the default package. If you want to make a package with a name, there is a keyword "package" that allows you to do it. For each class that will be included in your package, open the .java file for that class. Put this statement at the very beginning, before any import statements:
![]() package |
|
if you want the package's name to be "chess." By convention in Java, package names are lower case while class names are upper case. Then make sure that the .java file is saved in a directory that is also named "chess." Once the package is created, you can use it in other programs. If the files are not in the same directory, you just say:
import chess.*;
the same way you would import packages from Sun.
| Read more about access control: | Sun tutorial |
| David Eck's textbook The section on access is close to the bottom, after nested classes. | |
| Bruce Eckel's textbook |
| Previous Topic | Course Home Page | Syntax Sheet | Next Topic |