A C program is a collection of functions,
all at the same level and hence all on an equal footing. To unambiguously
designate where the computation starts, we insist that there is always a
function called main
where execution begins.
In a purely object-oriented language, a program is a collection of
classes. Every function and variable that is defined in the program must lie
within some class. However, as we have seen, classes are just templates and
their definitions come to life only after they are instantiated using new. Initially all classes are inactive and there is no way for
the program to get started—effectively, the program is deadlocked.
So, there is a need to be able to define functions whose existence does
not depend on a class being instantiated. There is another reason for having
such functions. Consider, for example, routine functions like read and write
(or scanf and printf, in C terminology), or, for example, mathematical functions
like sin, sqrt, . . . Clearly, it makes no sense to have to artificially
instantiate a class in order to use such functions.
One way to get around this problem without introducing free floating
functions that live outside classes (as happens, for instance, in C++) is to
add the qualifier static.
A function that is marked static inside a class is available without having to
instantiate the class. We could have a definition of the form
class IO {
public static ... read(...) { ... }
public static ... write(...) { ... }
...
}
and then invoke these functions from
outside as IO.read(...) and IO.write(...).
Static functions also solve the problem of where to start—like C, we can
insist that thecollection of classes includes one static function with a fixed
name (say, main,
like C) and begin execution by invoking this method.
In addition to static funtions, it also makes sense to have static data
variables. This can be used to define constants, such as:
class Math {
public static double PI = 3.1415927;
public static double E = 2.7182818;
public static double sin(double x) { ... }
...
}
Notice that the designation static is orthogonal to public/ private . Does it make senseto have something that is private
static ?
Though it appears useless at first sight, we could consider a class all
of whose instances needs some “magic numbers” to do their job, but where these
“magic numbers” need not be visible externally. Suppose we write a class that
computes the annual interest yield on a fixed deposit. Typically, the rate
varies depending on the length of the deposit, but it might be that all the
variable rates are computed from a single base rate. We might then write
class interest-rate {
private static double base_rate = 7.32;
private double deposit-amount;
public double threemonth-yield(){ ... } /* uses base-rate and
deposit-amount */
public double sixmonth-yield(){ ... } /* uses base-rate and
deposit-amount */
public double oneyear-yield(){ ... } /* uses base-rate */
and deposit-amount */
...
}
The idea is that all instances of
interest-rate share a single copy of the static variable base_rate, so that there is no unnecessary duplication of data and
also no inconsistency.Static variables are shared across all instances of a
class. Thus, we can also use static variables to keep track of global information
such as how many times a given function is called across all instances of the
class. For example, we could write
class stack {
private int values[100]; /*values are stored in an array */
private int tos = 0; /*top of stack, initialize to 0 */
private static int num_push = 0; /* number of pushes across
all stacks */
push (int i, ...){ /*
push i onto stack */
values[tos] = i;
tos = tos+1; /* Should check that tos < 100!! */
num_push++; /* update static variable */
}
...
}
Here again, it makes sense to have num_push restricted to be private because we want it to be
incremented only by the method push within the class stack.
We have to be careful when we mix static and non-static entities in the
same class. A non-static function is tied to a specific instance (object) and
so can implicitly refer to the current state of the object as well as to static
data (such as the yield functions above). However, since a static function is
shared amongst all instances of a class (and there need not even be a single
instance in existence for the static function to be used), such a function should
not make any reference to any non-static components of the class. We will
address this point in more detail later.
# Constants (the attribute final)
Consider our earlier definition
class Math {
public static double PI = 3.1415927;
...
}
The intention was to make the value
Math.PI available everywhere to use in expressions: e.g.,
area = Math.PI * radius * radius;
However, there is nothing to prevent the following improper update of
the public static field PI:
Math.PI
= 3.25;
To forbid this, we attach another attribute, indicating that a value but
may not be altered. Following Java terminology, we use the notation final, so we would modify the definition above to say:
class Math {
public static final double PI = 3.1415927;
...
}
and achieve what we set out to have—a
publicly available constant that exists without instantiating any objects. Actually,
the modifier
final has other ramifications. We will see
these later, when we
talk about inheritance.
Post a Comment