If the property is merely infrequently changed rather than truly immutable then a final field is not
appropriate. If the value of the field is not known when the object is created then it can't be made final,
even if it is logically immutable once known. For example, in a simulation of celestial bodies a comet may
become trapped by the gravitational pull of a star and commence to orbit that star. Once trapped the comet
orbits the star forever or until it is destroyed. In this situation the orbits field will hold an immutable value
once set, but that value is not known when the comet object is created and so the field cannot be final.
Finally, if initialization of the field is expensive and the field's value is infrequently needed, then it may be
more practical to defer the initialization of the field until its value is neededthis is generally termed lazy
initializationwhich cannot be done to a final field.
There are additional considerations concerning final fields if your object must be clonable or serializable.
These are discussed in "Cloning Objects" on page 101 and "Object Serialization" on page 549, respectively.
Exercise 2.4: Consider your solution to Exercise 2.3. Do you think the identification number field should be
final?
2.3. Access Control
If every member of every class and object were accessible to every other class and object then understanding,
debugging, and maintaining programs would be an almost impossible task. The contracts presented by classes
could not be relied on because any piece of code could directly access a field and change it in such a way as to
violate the contract. One of the strengths of object-oriented programming is its support for encapsulation and
data hiding. To achieve these we need a way to control who has access to what members of a class or
interface, and even to the class or interface itself. This control is specified with access modifiers on class,
interface, and member declarations.
All members of a class are always available to code in the class itself. To control access from other classes,
class members have four possible access modifiers:
- private Members declared private are accessible only in the class itself.
package Members declared with no access modifier are accessible in classes in the same package, as
well as in the class itself. We discuss packages and related accessibility issues in Chapter 18.
•
protected Members declared protected are accessible in subclasses of the class, in classes in the
same package, and in the class itself. Extending classes is covered in Chapter 3.
•
- public Members declared public are accessible anywhere the class is accessible.
The private and protected access modifiers apply only to members not to the classes or interfaces
themselves (unless nested). For a member to be accessible from a section of code in some class, the member's
class must first be accessible from that code.
It is important to realize that access control is performed on a per-class (or interface) level not on a per-object
level. This means that members of a class are always accessible from all code written in that class regardless
of which instance the code is being applied to. We illustrate this with an example later when we look at how
methods can also be used to control access; see Section 2.6.6 on page 65.
You should view public and protected members as contractual, because they can be relied on by code you do
not control. Changing them can be impossible after that code relies on public or protected functionality.
Package and private access are part of your implementation, hidden from outsiders (classes in the same
package should be related).
We declared the Body class's fields public because programmers need access to them to do the work the
class is designed for. In a later version of the Body class, you will see that such a design is not usually a good
idea.