Bruce Eckel’s Thinking in Java | Contents | Prev | Next |
Java, the access specifiers can also be used to determine which classes
within
a library will be available to the users of that library. If you want a class
to be available to a client programmer, you place the
public
keyword somewhere before the opening brace of the class body. This controls
whether the client programmer can even create an object of the class.
control the access of a class, the specifier must appear before the keyword
class.
Thus
you can say:
class Widget {
is, if the name of your library is
mylib
any client programmer can access
Widget
by saying
mylib.Widget;
mylib.*;
there’s an extra pair of constraints:
- There
can be only one
public
class per compilation unit (file). The idea is that each compilation unit has a
single public interface represented by that public class. It can have as many
supporting “friendly” classes as you want. If you have more than one
public
class inside a compilation unit, the compiler will give you an error message. - The
name of the
public
class must exactly match the name of the file containing the compilation unit,
including capitalization. So for
Widget,
the name of the file must be
Widget.java,
not
widget.java
or
WIDGET.java.
Again, you’ll get a compile-time error if they don’t agree. - It
is possible, though not typical, to have a compilation unit with no public
class at all. In this case, you can name the file whatever you like.
if you’ve got a class inside
mylib
that you’re
just
using to accomplish the tasks performed by
Widget
or some other
public
class in
mylib?
You don’t want to go to the bother of creating documentation for the
client programmer, and you think that sometime later you might want to
completely change things and rip out your class altogether, substituting a
different one. To give you this flexibility, you need to ensure that no client
programmers become dependent on your particular implementation details hidden
inside
mylib.
To accomplish this, you just leave the
public
keyword off the class, in which case it becomes friendly. (That class can be
used only within that package.)
that a class cannot be
private
(that
would make it accessible to no one but the class), or
protected.[26]
So you have only two choices for class access: “friendly” or
public.
If you don’t want anyone else to have access to that class, you can make
all the constructors
private,
thereby preventing anyone but you, inside a
static
member of the class, from creating an object of that class.
[27]
Here’s an example:
//: Lunch.java // Demonstrates class access specifiers. // Make a class effectively private // with private constructors: class Soup { private Soup() {} // (1) Allow creation via static method: public static Soup makeSoup() { return new Soup(); } // (2) Create a static object and // return a reference upon request. // (The "Singleton" pattern): private static Soup ps1 = new Soup(); public static Soup access() { return ps1; } public void f() {} } class Sandwich { // Uses Lunch void f() { new Lunch(); } } // Only one public class allowed per file: public class Lunch { void test() { // Can't do this! Private constructor: //! Soup priv1 = new Soup(); Soup priv2 = Soup.makeSoup(); Sandwich f1 = new Sandwich(); Soup.access().f(); } } ///:~
to now, most of the methods have been returning either
void
or a primitive type so the definition:
public static Soup access() { return ps1; }
look a little confusing at first. The word before the method name (
access)
tells what the method returns. So far this has most often been
void,
which means it returns nothing. But you can also return a handle to an object,
which is what happens here. This method returns a handle to an object of class
Soup.
class
Soup
shows how to prevent direct creation of a class by making all the constructors
private.
Remember that if you don’t explicitly create at least one constructor,
the default constructor (a constructor with no arguments) will be created for
you. By writing the default constructor, it won’t be created
automatically. By making it
private,
no one can create an object of that class. But now how does anyone use this
class? The above example shows two options. First, a
static
method is created that creates a new
Soup
and returns a handle to it. This could be useful if you want to do some extra
operations on the
Soup
before returning it, or if you want to keep count of how many
Soup
objects to create (perhaps to restrict their population).
second option uses what’s called a design
pattern
,
which will be discussed later in this book. This particular pattern is called a
“singleton”
because it allows only a single object to ever be created. The object of class
Soup
is created as a
static
private
member
of
Soup,
so there’s one and only one, and you can’t get at it except through
the
public
method
access( ).
previously mentioned, if you don’t put an access specifier for class
access it defaults to “friendly.” This means that an object of that
class can be created by any other class in the package, but not outside the
package. (Remember, all the files within the same directory that don’t
have explicit
package
declarations
are implicitly part of the default package for that directory.) However, if a
static
member of that class is
public,
the client programmer can still access that
static
member even though they cannot create an object of that class.
Actually, a Java 1.1
inner
class
can be private or protected, but that’s a special case. These will be
introduced in Chapter 7.
You can also do it by inheriting (Chapter 6) from that class.