Static variables and methods
Up to this point, we've made a big deal that all member fields in a class have separate copies in each instance of the class, so if we have two variables: Point one,two; then one.x is a different variable from two.x.
There is an exception to this. We can declare a member field as static. In that case the variable is shared between all instances.
class Point {
int x,y;
static int num;
}
In this case one.num is the same variable as two.num. If I change one.num, I have changed two.num as well.
This is handy for information that should be shared across all objects of the class. Imagine you wanted to establish a unique ID number to each object. Keeping a static field for the next free ID would be handy.
But, what is the value of num initially? We can't initialize it because we don't have an object yet in order to name it. The answer is to use the name of the class not the name of a variable instance of the class. We could make num 0 by saying Point.num=0; Note that this is only valid for static fields.
Stylistically, since we can always access num via the class name instead of a variable name, it has become preferred that we always do. This way it signals to the reader of our code that this is not a regular member field.
Another use for the static modifier on fields is in conjunction with final. Final means that the value of this thing cannot be changed, which makes it good for a constant:
class Tools {
final double SQRT2 = 1.41421356;
...}
but the problem with this is we couldn't access this thing without creating an object of type Tools:
Tools t = new Tools();
double d = t.SQRT2;
That seems wasteful, but if static fields exist even when no objects of that type exist, thaen we can declare it as:
class Tools {
final static double SQRT2 = 1.41421356;
...}
and access it directly using the class name:
double d = Tools.SQRT2;
We've seen the keyword static also applied to methods. A static method still is a member method of that class, but like static fields, it is not associated with any particular object. What this means is that inside this method, you cannot access any member fields that are not static. Consider adding the following to Point:
static int foo() {
return x;
}
If foo were not static, we could happily do one.foo(), and it would access the x field of the object one. But, since this is static, we would access this function as Point.foo(). So which object's x do we access? It's not clear!
The compiler agrees with your confusion. For this reason, we would get a
compile time error: "non-static variable x cannot be referenced from a
static context."
However, there is no impediment to accessing other static fields or functions:
static int foo() {
return num;
}
Static methods are used in 2 cases:
- When we only want to access static fields in the class, like the example above.
- When we don't need to access any of the state of an object because all the information we need is in the arguments. This is usually for utility functions that are best called in a structured/procedural way. The built in math functions are all examples of that: Math.pow(3,2);
public/private/protected
public on a field, function, or class means that anyone can access that thing; they can access the field, that method, or create on object of that class. So far, everything has been public.
As we move further along on this course, we'll get more and more into information hiding; that is, we want to restrict access to our fields, etc., to keep a clueless user from messing them up.
So what are the other options? The others are private, protected, or no modifier at all.
If a field or method is labelled private, it can only be accessed from inside that class. Consider the case of a Queue with member functions:
public class Queue {
private Node first;
private Node last;
public void push(String s){
//Some code
public String pop() {
//Some code
public String peek() {
//Some code
}
The fact that we have made first and last private means that it is impossible for code in some other class to say:
Queue q = new Queue(); q.first = somethingDestructive;
Instead, first and last can ONLY be changed by calling the functions push/pop/peek. We will discuss the benefits of this much more as we learn more about encapsulation.
Some of you might have accidently used no keyword, with no ill effects. This is called making the field/method/class package-private. What this means is that the item is accessable to other classes if and only if the other class is in the same package.
So what's a package? It's a grouping of related files explicitly bundled together. As a programmer you might create a collection of classes for a single purpose in a larger project, such as all the math related classes in a physics game; you can put them together as a package.
One main reason for packages is uniqueness of names, you can have the same name of a class as someone else on the project if they both are in different packages.
if you want to use something in another package, you have to reference it by name: java.util.Scanner s = new java.util.Scanner(in); or you can import it: import java.util.Scanner; Importing everything in a package makes name conflicts more likely.
To put something in a package, you put that package line as the first real line in your file. With no package line the file is still in a package, called the default package, along with everything else without a package name.
Packages have to be bundled together in the filesystem. The package edu.usna.cs.thispackagename has to be in the directory ./edu/usna/cs/thispackagename, so the compiler know where to look. In this case, everything needs to be compiled and run from the base directory.
This handy table from Sun explains access for the different keywords:
| Modifier | Class | Package | Subclass | World |
|---|---|---|---|---|
public |
Y | Y | Y | Y |
protected |
Y | Y | Y | N |
| no modifier | Y | Y | N | N |
private |
Y | N | N | N |
For now, we'll ignore that subclass column. This table introduces a new word, protected.
Note that no keyword gives us package access. Combined with everything being in the default package, this would make it the same as public, which might break our encapsulation. Be careful with that. If you explicitly want package access, you might want the protected keyword.