In this video lecture, we're going to talk
about a subset of Java classes which are exceptions
to the normal rules.
These are classes which are not used with
individual object instances, and we call these
static classes.
Okay, let's get started.
So at this point, we've talked about classes
as being the basic building blocks of any
Java program.
Using classes as our blueprints, we've shown
how to create individual instances of those
classes, or objects.
Once we have an object of a particular class
on hand, we can then make use of any of its
methods using dot notation.
The important thing we've emphasized to this
point is that methods are never called in
isolation, but rather always in the context
of existing objects.
It's always object-dot-method, as we see here.
For example, let's say that we create a CS12Date
object called halloween, and a string object
called label, with both objects shown here
in blue.
Then if we want to do anything with these
objects, we can call their various available
methods, shown here in red, but only in the
context of some specific object.
For example, the setDate() method of the CS12Date
class is called upon the halloween object,
and the toUpperCase() and length() methods
of the String class are called upon the label
object.
In all cases, it's object-dot-method, as we
see here.
This is the typical and the usual way of writing
object oriented code.
We sometimes refer to these as object methods.
But, we didn't really give you the full story.
Your mother and I weren't completely honest
with you.
As with anything, there are exceptions to
the general principle, which we want to discuss
next.
The exceptions to the usual object methods
are called static methods, or sometimes class
methods.
The key difference between object methods
and static methods, is that static methods
are called without having to instantiate any
specific object of the class.
Static methods are called from client application
code using the class name, rather than in
the context of any specific object using the
usual dot notation.
Here's the general form of calling some static
method.
It's class name-dot-method name, with the
class name as always beginning with a capital
letter, and shown here in green.
For example, we'll be taking a look at the
Math class shortly, and one of its methods
returns the absolute value of any number.
All the methods of the Math class, as we'll
see, our static methods.
So to call this method, it's Math.abs() with
some input value, and this entire right hand
side expression is the numerical value of
the absolute value.
Notice that there's no Math class object created,
here Math is the name of the class itself,
and not any object.
To create any static method, all we need to
do is simply add the static keyword before
the method return type, as shown here.
So here is the method interface for the absolute
value method.
The name of the method is abs(), it accepts
a double type input value, it returns a double
type result, and the entire method is a static
method.
Why do we have static methods anyway?
What static really means is that its elements
belong to the overall class, rather than to
any one specific object instance of the class.
Static methods are often useful because they
can provide quick and dirty, one time capability
for specific operations.
They don't require us to create and maintain
individual objects, or waste system resources,
when what we really want to do is just some
one simple, one-time thing.
As a prime example, consider the main method
interface, shown here, which we've seen many
times now, and we've said that every Java
application requires there to be at least
one of.
If you think about it, this is a classic chicken
and the egg problem.
When you begin execution of some program at
time 0, there hasn't yet been the opportunity
to create any objects yet, so there can be
no objects to call the main method upon.
We cannot do the usual object-dot-method thing,
so we must call the main method in the absence
of any specific objects.
And this, therefore, is why the main method
is itself a static method: it's called in
the absence of any specific object.
We want to run the method once, and then we're
done with it until next time.
Here are some other examples of where we might
encounter static methods, and we'll be going
over these in the coming several lecture topics.
For example, we said that the methods of the
Math class are static methods.
If we want to perform some simple mathematical
calculations, we really don't want to have
to create math objects and carry them around,
when all we want is just a simple result.
If we want to get some input value from a
user using a pop-up dialog box, we just want
to quickly throw up that dialog box, get the
result, and move on, without the overhead
of instantiating some dialog box object.
And as we'll see shortly, in the context of
using pop-up dialogs for user input, we'll
soon need a way to convert from text input
to numerical values, and for this we'll use
several datatype wrapper methods.
As you might imagine, all of these are example
situations where we might need just some quick
and dirty one-time functionality, without
having to carry around any object instances
for the ride.
These are situations where static methods
will come into play.
To compare and contrast object methods versus
static methods, let's take a look back at
an example we've already seen when talking
about methods.
You may want to take a moment now to pull
up the indicated source code example files
in jGRASP, and perhaps revisit their short
code walk-thru video.
On the left side, we see the MethodExamples
class, which is simply a collection of three
short methods to add three numbers, calculate
a percentage, and print a formatted message,
along with another method which itself calls
the other three methods internally.
To use these methods, we must first create
a method examples object using a default constructor,
as shown here.
Now, the observant among you might recognize
that there ARE no constructors specified in
the MethodExamples class, which means this
is simply an automatically created constructor,
but we're kind of glossing over that fact
for now.
The important point here is that we are creating
a new object obj.
Then once we have this object on hand, notice
that we can call any of the methods on the
left using dot notation together with the
obj object.
This is the object-dot-method usage form,
and we have 5 instances of this in the client
program on the right, as shown here, here,
here, here, and here.
Again this is the usual and typical way of
doing things in object oriented programming.
By contrast, here is the exact same utility
class on the left side, except that the class
has been renamed to MethodStaticExamples,
and now each of the methods has become a static
method by introduction of this extra static
keyword to its interface.
Other than that, each of these methods is
exactly the same as before.
Because these are now static methods, how
we call or invoke them has now changed in
this updated client application on the right.
For starters, notice that there is no longer
any creation of any object needed.
Now, we are calling the same 5 methods in
the same way, except that instead of calling
them in the context of some object, now we
are calling them using the name of the class
itself.
Here there is NO intervening object involved,
it's instead class-dot-method.
Please take a moment now to pause this video,
and view the short code walk-thru video for
MethodStaticExamples.java and MethodStaticExamplesClient.java.
Open up these files in jGRASP, so you can
follow along.
You'll find these example in the usual place.
Come back to this video when you are finished.
We just saw an example of a class containing
several static methods.
Well, it turns out that we can also have classes
which contain static data as well.
Data in Java programs becomes static when
it is declared using the static keyword before
its data type.
Such static data is not specific to each individual
object instance, but instead belongs to the
class as a whole.
One typical usage of static data might be
to keep track of how many individual instances,
or objects, of that class have been created.
Each time a new object instance is created,
its constructor would increment that one common
static count variable, and every such object
would have access to that one shared count
variable.
We'll take a closer look at this later in
the course, when we learn how to create our
own classes, but for now we'll let it go at
this.
One very common usage of static data is for
named static constants, or class constants,
such as for the Math class or the Color class.
Just as for static methods, static constants
are accessed using their class name rather
than in the context of any specific object.
For example, there is a math constant for
pi called Math.PI, and a specific RGB color
value called Color.BLUE.
Notice that in each case, as per good conventions,
the name of the class is capitalized to indicate
that it is a class, and that the variable
name is capitalized to indicate that it is
a constant.
But wait a minute!
Didn't we say earlier that one of the good
practices of object oriented programming was
to keep all data as private, and only access
it using public accessor and mutate or methods?
Wasn't the goal to prevent outside corruption
of data by preventing any direct access to
that data, thereby maintaining data encapsulation?
Well, it turns out that here for static constants,
we are still maintaining the spirit of data
encapsulation by typically always declaring
such data as final, which means that once
its value is set internally, it cannot be
changed.
So even for static constants, even though
we reference them by name directly without
using accessor (or get) methods, we also can't
alter their values anyway by using mutator
(or set) methods.
We do this simply because in such cases, it's
often just easier to have direct access by
name to such constant data.
As always in life, there's often the fine
print.
Here are the restrictions when using static
methods.
Static methods can only access other outside,
class level static data.
They cannot access any instance variables
of their class, for the simple reason that
it's entirely possible that no objects of
that class might yet exist.
Notice the careful use of the word outside
here.
Of course, any method can always refer to
or access any variables which are locally
declared inside that method.
Here we are only referring to the access to
any outside data.
And finally, static methods can only directly
call or invoke other static methods.
As our go-to example, consider again the main()
method.
We've now been reminded that the main() method
is in fact a static method.
At program startup, there are no other objects
yet in existence to call the main() method
upon.
So to be truly standalone, and to get the
program execution ball in motion, the main()
method must itself be static.
Therefore, if you want to carve up your program
into additional methods which will be located
within the same class as main() itself, and
you want to call those methods directly by
name from main(), any such methods must also
themselves be declared as static.
So to sum up the preceding discussion, here
is a revised generic class structure diagram.
As we've said, now there are two types of
data and methods, the added type being static,
as shown here in green.
These static methods can only access other
static data, such as here.
These static methods cannot access any normal
object-specific instance variable data, since
no objects of this type might yet exist.
Also, the static methods can only directly
call other static methods of this class.
However, the converse is not true.
Any of these object methods can access this
static data, provided that it's also public,
because static data belongs to the class and
not to any specific object instance of the
class.
Also, for the same reasons, object methods
can access static methods of their own class
or any other class, again provided that those
methods are also public, by using class.method
notation as shown here.
Okay, that's enough on static methods for
now.
This has probably been a bit more information
then we really need right now, but now we're
in a position to look at some static class
examples and make better sense of all this.
