Making members public or private
static is a declaration modifier: it changes, or “modifies” the declaration. In the case of static, it restricts the class member (field or method) to a single instance. There's another kind of modifier, called an “access” modifier, that puts restrictions on access to a class member.
There are five access modifiers in total, but in this section we will explain only three of them: public, private, or default. private is the simplest, so let's start with that.
private access
Suppose field a is private in class B (i.e., its declaration starts with the private modifier). The effect of this is that a is accessible only from methods within class B. If code in any other class makes a reference to a, the Java compiler will report an error and refuse to compile that code. The same goes for methods: suppose method c is private in class B. If code in any other class invokes c, the Java compiler will report an error and refuse to compile that code.
Why would you declare a member private? Let's consider the Distance class we've developed in previous sections. Let's look at it in its simplest form, without the convenience methods.
class Distance {
double value;
Units units;
}
As declared, the fields of Distance are not private, and nothing prevents us from assigning values to them, like we did before:
Distance detToChi = new Distance(); detToChi.value = 282.0; detToChi.units = Units.Miles;
Suppose you wanted to ensure that the value field and the units field were always assigned together, like in the code above? This would make sense, because the value of a measurement and the units of that measurement are inseparable. But with the simple class declaration above, you have no way of doing that. With that class declaration, you are not able to prevent someone from assigning a value to the value field without assigning a value to the units field. If they do that, they will have a Distance object with a value but no units.
The private access modifier helps you prevent this situation. You use it as part of a two-part solution. First, declare both fields private; second, provide a “setter” method.
class Distance {
private double value;
private Units units;
void setValue(double newValue, Units newUnits) {
value = newValue;
units = newUnits;
}
}
This solution prevents code that is outside the Distance class from accessing the value and units directly. That code can only use the setValue method. Since setValue requires values for both the value and the units fields, this prevents users of the class from forgetting to set the units of the distance. The code above that creates the detToChi Distance object would now look like this:
Distance detToChi = new Distance(); detToChi.setValue(282.0, Units.Miles);
Packages
To understand the public access modifier and default access, we need to introduce packages. Every Java class belongs to a package. If you do not explicitly declare what package a class is in (by putting a package statement as the first statement in a class declaration), the Java compiler puts it in the default package.
In Elemental Java, we will always put our classes in the default package, so we won't include package statements in our code. In code for which you you have a serious purpose you should use a package statement, but the default package works for our current purposes. For now, it is sufficient to be aware that all Java code belongs to one package or another, and that if there is not a package statement at the top of the class declaration, that class is put in the default package.
default access
Class members that do not have an access modifier have default access. Class members with default access can be accessed by code from any class that is in the same package as the class the member belongs to. In the Distance class declaration above, the value and units fields have private access and the setValue method has default access.
public access
When you declare a member to have public access, you are allowing that member to be accessed from classes in any package. It is the least restrictive of the access modifiers. In the Distance class example, there is no reason not to allow any class to access the setValue method, so we might as well make it public:
class Distance {
private double value;
private Units units;
public void setValue(double newValue, Units newUnits) {
value = newValue;
units = newUnits;
}
}
If all the code you write for a program is in the same package, the public access modifier not have much purpose. But you will at least need it for one method: your class's main method: public static void main(String[] args). If main is not public, Java can not run your program.
For our purposes in Elemental Java, default access is perfectly fine. However, in “real-life” code, we typically do not use default access. Instead, we prefer to use either private or public access. It's simpler to decide whether a field or method is safe to access within its own class only (private) or is safe to access by anybody (public), than it is to decide whether it is safe to access from classes within the same package (default access) but not from classes outside the same package.
The final modifier
The final modifier is not an access modifier, but now that we know about the public and static modifiers, we can introduce a modifier that is often used with them, which is the final modifier. final prevents modification of a field after it is initialized. Consider the Distance class declaration from a previous section:
class Distance {
double value;
Units units;
static double KILOMETERS_PER_MILE = 1.609;
double inKilometers() {
return units == Units.Kilometers ? value : value * KILOMETERS_PER_MILE;
}
}
For the integrity of the Distance class, we should prevent the KILOMETERS_PER_MILE field from being modified. We can do this with the private access modifier, because that will prevent any code from outside the class from accessing the field, and we can police ourselves to make sure we don't modify it in code in methods within Distance. But what if want to make this constant available as a feature of the class? For that, it has to be public. But then it is accessible from outside the class, and therefore modifiable.
If we add final to the declaration of the KILOMETERS_PER_MILE field, it cannot be modified after initialization, which is done only once, when the field is declared. So adding this, and the appropriate access modifiers on the other members, gives us:
class Distance {
private double value;
private Units units;
public static final double KILOMETERS_PER_MILE = 1.609;
public double inKilometers() {
return units == Units.Kilometers ? value : value * KILOMETERS_PER_MILE;
}
}