JavaThe Essence of OOP using Java: Static Members

The Essence of OOP using Java: Static Members

Java Programming Notes #1620


Preface


This lesson is one of a series of lessons designed to teach you about the
essence of Object-Oriented Programming (OOP) using Java. The first lesson in the group was entitled The
Essence of OOP Using Java, Objects, and Encapsulation
.  That lesson,
and each of the lessons following that one, has provided explanations of certain aspects of the essence of Object-Oriented Programming using Java. The previous lesson was entitled The Essence of OOP using Java, Polymorphism and Interfaces, Part 2.

Necessary and significant aspects

This miniseries will describe and discuss the necessary and
significant aspects of OOP using Java. If you have a general understanding of computer programming, you should be able to read and understand the lessons in this miniseries, even if you don’t have a strong background in the Java programming language.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find those lessons published at Gamelan.com.
However, as of the date of this writing, Gamelan doesn’t maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there.  You will find a consolidated index at Baldwin’s Java Programming Tutorials.

Preview


Static members

There is another aspect of OOP in Java that I have avoided up to this point in the discussion: static variables and static methods.

Tends to complicate …

I have avoided this topic because, while not particularly difficult,
the existence of static members tends to break up the simple structures
that I have discussed in previous lessons in this miniseries.

While static members can be useful in some situations, the existence
of static members tends to complicate the overall object-oriented structure
of Java.

Avoid overuse of static members

Furthermore, the overuse of static members can lead to problems similar
to those experienced in languages like C and C++ that support global variables
and global functions.

When to use static members

I will discuss the use of static members in this lesson, and will provide
some guidelines for their use.

The class named Class

I will also introduce the class named Class and discuss how it
enters into the use of static variables and methods.

Instance members vs.. class members

I will describe the differences between instance members and
class members with particular emphasis being placed on their accessibility.

Three kinds of objects

From a conceptual viewpoint, there are at least three kinds of objects
involved in a Java program:

  • Ordinary objects
  • Array objects
  • Class objects

Ordinary objects

All of the discussion up to this point in the miniseries deals with
what I have referred to in the above list as ordinary objects.

These are the objects that you instantiate in you code by applying the
new
operator to a constructor for a class in order to create a new instance
(object)
of that class.  (There are also a couple of other ways to create
ordinary objects, but I’m not going to get into that at this time.)

Array objects

I haven’t discussed array objects thus far in this miniseries.
(I
plan to discuss them in a subsequent lesson.)

Suffice it for now to say that Array objects are objects whose purpose
is to encapsulate a one-dimensional array structure that can contain either
primitive values, or references to other objects (including other Array
objects).

I will discuss Class objects in this lesson.

Discussion
and Sample Code


Class objects

Let me emphasize at the beginning that the following discussion is conceptual
in nature.  In this discussion, I will describe how the Java system
behaves, not how it is implemented.  In other words, however it is
implemented, it behaves as though it is implemented as described below.

The class named Class

There is a class whose name is Class.  The purpose of this
class is to encapsulate information about some other class (actually,
it can also be used to encapsulate information about primitive types as
well as class types).

Here is part of what Sun has to say about this class:

“Instances of the class Class represent classes and
interfaces in a running Java application. …

Class has no public constructor. Instead Class objects
are constructed automatically by the Java Virtual Machine as classes are
loaded …”

What does this mean?

As a practical matter, when one or more objects are instantiated from
a given class, an extra object of the Class class is also instantiated
automatically.  This object contains information about the class from
which the objects were instantiated.

(Note that it is also possible to cause a Class object
that describes a specific class to be created in the absence of objects
of that class, but that is a topic that will be reserved for more advanced
lessons.)

A real-world analogy

Here is an attempt to describe a real-world analogy.  Remember
that a class definition contains the blueprint for objects instantiated
from that class.

A certain large construction company is in the business of building
condominium projects.  This contractor builds condos of many different
sizes, types, and price ranges.  However, each different condo project
contains condos of only two or three different types or price ranges.

A library of blueprints

There is a large library of blueprints at the contractor’s central office. 
This library contains blueprints for all of the different types of condos
that the contractor has built or is building.  (This library is
analogous to the class libraries available to the Java programmer.)

A subset from the blueprint library

When a condo project begins, the contractor delivers copies of several
sets of blueprints to the construction site.  The blueprints delivered
to that site describe only the types of condos being constructed on that
site.

Condo is analogous to an object

Each condo unit is analogous to an ordinary Java object.

Each set of blueprints delivered to the construction site is roughly
analogous to an object of the class named Class.  In
other words, each set of blueprints describes one or more condo units constructed
from that set of blueprints.

When construction is complete

When the construction project is complete, the contractor delivers a
set of blueprints for each type of condo unit to the management firm that
has been hired to manage the condo complex.  Each set of blueprints
continues to be analogous to an object of the class named Class
The blueprints remain at the site of the condo units.

RTTI

Thus, information regarding the construction, wiring, plumbing, air
conditioning, etc., for each condo unit (object) continues to be
available at the site even after the construction has been completed.

(This is somewhat analogous to something called runtime
type information and often abbreviated as RTTI.  A Class object contains
RTTI for objects instantiated from that class.)

What are those analogies again?

In the above scenario, each condo unit is (roughly) analogous
to an object instantiated from a specific class (set of blueprints).

Each set of blueprints remaining onsite after construction is complete
is roughly analogous to a Class object that describes the characteristics
of one or more condo units.

What do you care?

Until you get involved in such advanced topics as reflection
and introspection, you don’t usually have much involvement or much
interest in Class objects.  They are created automatically,
and are primarily used by the Java virtual machine during runtime to help
it do the things that it needs to do.

An exception to that rule

However, there is one area where you will be interested in the use of
these Class objects from early on.  You will be interested
whenever variables or methods in the class definition are declared to be
static.

Class variables and methods

According to the current jargon, declaring a member variable to be static
causes it to be a class variable.

(Note that local variables cannot be declared static
Only member variables can be declared static.)

Similarly, declaring a method to be static causes it to be a class
method.

Instance variables and methods

On the other hand, according to the current jargon, not declaring a
variable to be static causes it to be an instance variable,
and not declaring a method to be static causes it to be an instance
method
.

In general, we can refer to them as class members and instance
members
.

What is the difference?

Here are some of the differences between class and instance
members insofar as this discussion is concerned.

How many copies of member variables exist?

Every object instantiated from a given class has its own copy of each
instance variable defined in the class.

(Instance variables are not shared among objects.)

However, every object instantiated from a given class shares the same copy
of each class variable defined in the class.

(It is as though the class variable belongs to the single
Class object and not to the individual objects instantiated from that class.)

Access to an instance variable

Every object has its own copy of each instance variable (the object
owns the instance variable).
  Therefore, the only way that you
can access an instance variable is to use that object’s reference to send
a message to the object requesting access to the variable (even then,
you may not be given access, depending on access modifiers).

Why call it an instance variable?

According to the current jargon, an object is an instance of a
class
.

(I probably told you that somewhere before in this miniseries. 
At least, I hope that I did.  After writing eight or ten lessons in
a miniseries, I sometimes forget what I told you before.)

Each object has its own copy of each non-static variable.  Hence,
they are often called instance variables.  (Every instance of the
class has one.)

Access to a class variable

You can also send a message to an object requesting access to a class
variable that the object shares with other objects instantiated from the
same class.  (Again, you may or may not gain access, depending
the access modifiers).

Access using the Class object

More importantly, you can also access a class variable without a requirement
to go through an object instantiated from the class.  (In fact,
a class variable can be accessed in the total absence of objects of that
class.)

(Remember, this discussion is conceptual in nature, and
may not represent an actual implementation.)

Assuming that a class variable is otherwise accessible, you can access
the class variable by sending an access request message to the Class
object to which the variable belongs.

One way to think of this

To help you keep track of thing in a message-passing sense, you can
pretend that there is a global reference variable whose name is the same
as the name of a class.

This (hypothetical) reference variable contains a reference to
the Class object that owns the class variable.  Using standard
Java message-passing syntax, you can access the class variable by joining
the name of the reference variable to the name of the class variable with
a period.  Example syntax is shown below:

ReferenceVariableName.ClassVariableName

As a result of the hypothetical substitution process that I described
above, this is equivalent to the following:

ClassName.ClassVariableName

We will see an example of this in the sample program that I will discuss
later.

Be careful with this thought process

While this thought process may be useful when thinking about static
variables and methods, I want to point out, that the thought process breaks
down very quickly when dealing with Class objects in a deeper sense.

For example, when invoking the getName method on a Class
object, an actual reference of type Class is required to access
the members of the Class object.  The name of the class will
not suffice.

If this discussion of a global reference variable whose name matches
the name of the class is confusing to you, just forget it.  Simply
remember that you can access class variables by joining the name of the
class to the name of the class variable using a period as the joining operator.

Characteristics of class methods

I’m not going to talk very much about instance methods and class methods
in this lesson.  However, there are a couple of characteristics of
class methods that deserve a brief discussion in this context.

Cannot access instance members

First, the code in a class method has direct access only to other static
members of the class.

(A class method does not have direct access to instance
variables or instance methods of the class.)

This is sort of like saying that a class method has access to the methods
and variables belonging to the Class object, but does not have access
to the methods and variables belonging to the ordinary objects instantiated
from the class described by the Class object.

Once again, be careful

Once again, this thinking breaks down very quickly once you get beyond
static members.  A Class object also has instance methods,
such as getName, which can only be accessed using an actual reference
to the Class object.

Now you are probably beginning to understand why I deferred this
discussion until after I finished discussing the easy stuff.

No object required

Another important characteristic is that a class method can be accessed
without a requirement for an object of the class to exist.

As with class variables, class methods can be accessed by joining the
name of the class to the name of the method with a period.

I will illustrate much of this with a sample program named MyClass01.

Discuss in fragments

I will discuss the program in fragments.  You will find a complete
listing of the program in Listing 13 near the end of the lesson.

Listing 1 shows the beginning of the class definition.

 

class MyClass01{
  static Date v1 = new Date();
  Date v2 = new Date();

Listing 1

Two member variables

The code in Listing 1 declares two member variables, named v1
and v2, and initializes each of those variables with a reference
to a new object of the Date class.

(When instantiated using the constructor with no arguments,
the new Date object encapsulates the current date and time from
the system clock.)

Note the static keyword

The important thing to note here is the use of the static keyword
when declaring the variable named v1.  This causes v1
to be a class variable, exhibiting the characteristics of class
variables described earlier.

An instance variable

On the other hand, the variable named v2 is not declared static
This causes it to be an instance variable, as described above.

The main method is a class method

Listing 2 shows the signature for the main method.

 

  public static void main(
                        String[] args){

Listing 2

The important thing to note here is that the main method is declared
static
That causes it to be a class method.

As a result, the main method can be invoked without a requirement
for an object of the class to exist.

(Also, the main method has direct access only to other static
members.)

How a Java application starts running

In fact, that is how the Java Virtual Machine starts an application
running.

First the JVM finds the specified file having an extension of
.class.
  Then it examines that file to see if it has a main
method with the correct signature.  If not, an error occurs.

If the JVM finds a main method with the correct signature, it
invokes that method without instantiating an object of the class. 
That is how the Java Virtual Machine causes a Java application to start
running.

A side note regarding applets

For those of you who are familiar with Java applets, you should
know that this is not the case for an applet.  You should know that
an applet does not use a main method.  When an applet is started,
an object of the controlling class is instantiated by the browser, by the
appletviewer
program, or by whatever program is being used to control the execution
of the applet.

A poor programming technique

Basically, this entire sample program is coded
inside the main method.  As a practical manner, that is a very
poor programming technique, but it works well for this example.

Display some text

The code in Listing 3, which is the first executable statement in the
main
method, causes the words Static variable to appear on the computer
screen.  I will come back and discuss the details of this and similar
statements later in the lesson.

 

    System.out.println(
                    "Static variable");

Listing 3

Display date information

Proceeding down through the code in the main method, the code
in Listing 4 causes the current contents of the Date object referred
to by the contents of the class variable named v1 to be displayed
on the computer screen.

 

    System.out.println(MyClass01.v1);

Listing 4

No object required

For the moment, concentrate on the boldface text in the statement in
Listing 4.

IMPORTANT:  Because the variable named v1 is a class
variable, it’s value is accessed by joining the name of the class to the
name of the variable with a period.

What was the output?

I will also discuss the remaining portion of statements of this sort
later.  For now, just be aware that it caused the output shown in
Figure 1 to be displayed on my computer screen when I ran the program.

 

Mon Sep 17 09:52:27 CDT 2001

Figure 1

Displays date and time

Obviously, the date and time displayed will depend on when you run the
program.

Pay particular attention to the seconds portion of the time.  I
will refer back to this later.

A five-second delay

The code in Listing 5 (still in the main method) causes
the main thread of the program to go to sleep for five seconds.  Don’t
worry about it if you don’t understand this code.  The only reason
that I included it in the program was to force a five-second delay in the
execution of the program.

 

  try{
    Thread.currentThread().sleep(5000);
  }catch(InterruptedException e){}

Listing 5

Instantiate a new object

Having caused the program to sleep for five seconds, the code in Listing
6 instantiates a new object of the class named MyClass01
The code stores the new object’s reference in the reference variable named
ref1.

 

    MyClass01 ref1 = new MyClass01();

Listing 6

A new Date object also

Recall from Listing 1 above that the class declares an instance variable
named v2 of the type Date.

When the new object is instantiated by the code in Listing 6, a new
Date
object is also instantiated.  A reference to that object is stored
in the instance variable named v2.

(In other words, the new object of the class MyClass01
owns a reference to a new object of the class Date.  That reference
is stored in an instance variable named v2 in the new MyClass01
object.)

Display the new Date object

The code in Listing 7 causes a textual representation of the new Date
object referred to by the reference variable named v2 belonging
to the object referred to by the reference variable named ref1,
to be displayed on the standard output device.

 

    System.out.println(ref1.v2);

Listing 7

Five seconds later

This code caused the date and time shown in Figure 2 to appear on the
computer screen when I ran the program:

 

Mon Sep 17 09:52:32 CDT 2001

Figure 2

If you note the time in the above output, you will see that it is five
seconds later than the time reflected in the Date object referred
to by the class variable named v1.  That time was displayed
by the code in Listing 4 earlier.

So, what does this mean?

It means that the Date object referred to by the static
reference variable named v1 was created five seconds earlier than
the Date object referred to by the instance variable named v2.

When is a class variable created?

I can’t tell you precisely when a class variable comes into existence. 
All I can say is that the virtual machine brings it into existence as soon
as it is needed.

My guess is that it comes into existence at the first mention (in
the program)
of the class to which it belongs.

When is an instance variable created?

An instance variable doesn’t come into existence until the object to
which it belongs is created (an instance variable cannot exist until
the object to which it belongs exists)
.

If the instance variable is initialized with a reference to a new object
(such
as a new Date object in this sample program),
that new object comes
into existence when the object to which it belongs comes into existence.

A five-second delay

In this program, I purposely inserted a five-second delay between the
first mention of the class named MyClass01 in Listing 4, and the
instantiation of the object of the class named MyClass01 in Listing
6.

As a result, the Date object referred to by the instance variable
named v2 was created about five seconds later than the Date
object referred to by the class variable named v1.

This is reflected in the date and time values displayed and discussed
earlier.

Accessing class variable via an object

While it is possible to access a class variable using the name of the
class joined to the name of the variable, it is also possible to access
a class variable using a reference to any object instantiated from the
class.

(As mentioned earlier, if two or more objects are instantiated
from the same class, they share the same class variable.)

The boldface code in Listing 8 uses the reference variable named ref1
to access the class variable named v1, and to cause the contents
of the Date object referred to by the class variable to be displayed.

 

    System.out.println(ref1.v1);

Listing 8

The output

This caused the date and time shown in Figure 3 to be displayed on my
computer screen.

 

Mon Sep 17 09:52:27 CDT 2001

Figure 3

Same date and time

As you have probably already surmised, this is the same date and time
shown earlier in Figure 1.  This is because the code in Listing 8
refers to the same class variable as the code in Listing 4.  Nothing
has caused the contents of that class variable to change, so both Figure
1 and Figure 3 display the contents of the same Date object.

(Only one class variable exists and it doesn’t matter how
you access it.  Either way, you gain access to the same Date
object whose reference is stored in the class variable.  Thus, the
same date and time is shown in both cases.)

Another new object

If you examine the code in Listing 13 near the end of the program, you
will see that an additional five-second delay is introduced at this point
in the program.

Following that delay, the code in Listing 9 instantiates another new
object of the class named MyClass01, and stores the object’s reference
in a new reference variable named ref2.

(The object referred to by ref1 is a different object
than the object referred to by ref2.  Each object has its own
instance variable named v2, and in this case, each instance variable
is initialized to instantiate and refer to a new Date object when
the new MyClass01 object is instantiated.)

    MyClass01 ref2 = new MyClass01();

Listing 9

Display the date and time

Then, the code in Listing 10 causes the contents of the Date
object referred to by the instance variable named v2 in the second
object of the class named MyClass01 to be displayed.

 

    System.out.println(ref2.v2);

Listing 10

This caused the output shown in Figure 4 to be displayed on my computer
screen when I ran the program (again, you will get different results
if you compile and run the program because the date and time shown is the
date and time that you run the program)
.

 

Mon Sep 17 09:52:37 CDT 2001

Figure 4

Five seconds later

As you have probably figured out by now, the time encapsulated in this
Date
object is five seconds later than the time encapsulated in the Date
object displayed in Figure 2.  This is because the program was put
to sleep for five seconds between the instantiation of the two objects
referred to by ref1 and ref2.

Every object has one

Every object instantiated from a given class has its own copy of each
instance variable declared in the class definition.  There is no sharing
of instance variables among objects.

Each instance variable comes into existence when the object to which
it belongs comes into existence, and ceases to exist when the object to
which it belongs ceases to exist.

(If the instance variables are reference variables holding
references to other objects, as is the case here, and if there are no other
reference variables holding references to those same objects, the secondary
objects cease to exist when the primary objects cease to exist.  Technically,
the objects may not cease to exist.  Technically they become eligible
for garbage collection, which means that the memory that they occupy becomes
eligible for reuse.  However, as a practical matter, they cease to
exist insofar as the program is concerned.  They are no longer accessible.)

Since the two objects referred to by ref1 and ref2 came into
existence with a five-second delay, the Date objects belonging to
those two object reflect a five-second difference in the time encapsulated
in the objects.

Only one copy of class variable exists

Also remember that if a variable is a class variable, only one copy
of the variable exists, and all objects instantiated from the class share
that one copy.

This is illustrated by the code in Listing 11, which uses the reference
to the second object instantiated from the class named MyClass01,
to cause the contents of the class variable named v1 to be displayed.

 

    System.out.println(ref2.v1);
  }//end main

Listing 11

The output produced by the code in Listing 11 is shown in Figure 5.

 

Mon Sep 17 09:52:27 CDT 2001

Figure 5

Same output as before

As you can see, this is the same as the output shown in Figure 1 and
Figure 3 earlier.

Accessing the same physical class variable

Since only one class variable named v1 exists, and all objects
instantiated from the class named MyClass01 share that single copy,
it doesn’t matter whether you access the class variable using the name
of the class, or access it using a reference to either of the objects instantiated
from the class.  In all three cases, you are accessing the same physical
class variable.

Since nothing was done to cause the contents of the class variable to
change after it came into existence and was initialized, Figures 1, 3,
and 5 are simply three different displays of the date and time encapsulated
in the same Date object whose reference is stored in the class variable.

Let’s revisit System.out.println…

Now, I want to revisit the statement originally shown in Listing 8 and
repeated in Listing 12 for viewing convenience.

 

    System.out.println(ref1.v1);

Listing 12

Java programmer wanted

I often tell my students that if I were out in industry, interviewing
prospective Java programmers, my first question would be to ask the prospective
employee to tell me everything that she knows about the statement in Listing
12.

Covers a lot of Java OOP technology

This is not because there is a great demand for the use of this statement
in real-world problems.  (In fact, in a GUI-driven software product
world, there is probably very little demand for the use of this statement.)
 
Rather, it is because a lot of Java object-oriented technology is embodied
in this single statement.

In that scenario, I would expect to receive a verbal dissertation of
fifteen to twenty minutes in length to cover all the important points.

The short version

Let me give you the short version.  There is a class named System.
The System class declares three static (class) variables
having the following types, names, and modifiers:

  • public static final PrintStream out
  • public static final InputStream in
  • public static final PrintStream err

(Note that these class variables are also declared final,
causing them to behave as constants.)

Access the out variable without an object

Because out is a class variable, System.out returns the
contents of the class variable named out (an object of the System
class is not required in order to access a class variable of the System
class).

In general, (ignoring the possibility of subclasses and interfaces)
because out is a reference variable of type PrintStream,
the returned value must either be null (no object reference)
or a reference to a valid PrintStream object.

Object of the PrintStream class

When the Java Virtual Machine starts an application running, it instantiates
an object of the PrintStream class and connects it to the standard
output device
.

(By default, the standard output device is typically the
computer screen, but it can be redirected at the operating system level
to be some other device.  The following discussion assumes that the
screen is the standard output device.)

Assign object’s reference to out variable

When the PrintStream object is instantiated by the virtual machine,
the object’s reference is assigned to the class variable of the System
class named out.

(Because the variable named out is final, the contents
of the variable cannot be modified later.)

Reference to a PrintStream object

Therefore, the expression System.out returns a reference to the
PrintStream
object, which is connected to the standard output device.

Many instance methods

An object of the PrintStream class contains many instance methods. 
This includes numerous overloaded versions of a method named println
The signature of one of those overloaded versions of the println
method follows:

public void println(Object x)

Textual representation of an object

The purpose of this overloaded version of the println method
is to:

  • Create a textual representation of the object referred to by the incoming
    parameter of type Object (because Object is a totally
    generic type, this version of the println method can accept an incoming
    parameter that is a reference to any type of object)
  • Send that textual representation to the output device

In general …

(In general, a new PrintStream object can be connected to
a variety of output devices when it is instantiated.  However, in
the special case of the PrintStream object instantiated by the virtual
machine when the program starts, whose reference is stored in the class
variable named out of the System class, the purpose of the
object is to provide a display path to the standard output device.)

Our old friend, the toString method

To accomplish this, the code in the println method invokes the
toString
method on the incoming reference.

(I discussed the toString method in detail in earlier
lessons in this miniseries.)

The toString method may, or may not, have been overridden in the
definition of the class from which the object was instantiated, or in some
superclass of the class from which the object was instantiated.

Default version of toString

If not overridden, the default version of the toString method
defined in the Object class is used to produce a textual representation
of the object.  As we learned in an earlier lesson, that textual representation
looks something like the following:

[email protected]

Overridden version of toString method

If the class from which the object was instantiated (or some superclass
of that class)
contains an overridden version of the toString
method, runtime polymorphism kicks in and the overridden version of the
method is executed to produce the textual representation of the object.

The Date class overrides toString

In the case of this sample program, the object was instantiated from
the Date class.  The Date class does override the toString
method.

When the overridden toString method is invoked on a Date
object’s reference, the String returned by the method looks something
like that shown in Figure 6.

 

Mon Sep 17 09:52:27 CDT 2001

Figure 6

You will recall that this is the output that was produced by the code
shown in Listing 8 and Listing 12.

More than you ever wanted to know …

And that is probably more than you ever wanted to know about the expression
System.out.println….

It is also probably more than you ever wanted to know about class variables,
class methods, instance variables, and instance methods.

Some cautions

Before leaving this topic, I do want to express some cautions. 
Basically, I want to suggest that you use static members very sparingly,
if at all.  Several good sets of guidelines have been published regarding
the use of static members.  As of this writing, you can find one of
them, written by Mark L. Fussell, at the following URL.

Guidelines for use of static members

I will try to summarize the general sense of most published guidelines
in a few words.

Static variables

To begin with, don’t ever use static variables without declaring them
final
unless you understand exactly why you are declaring them static.

(Static final variables, or constants, are often
very appropriate.  See the fields in the Color class for example.)

I can only think of a few situations where the use of a non-final static
variable might be appropriate.

(One appropriate use might be to count the number of objects
instantiated from a specific class.  I suspect there are a few other
appropriate uses as well.)

Static methods

Don’t declare methods static if there is any requirement for the method
to remember anything from one invocation to the next.

There are many appropriate uses for static methods, but in most cases,
the purpose of the method will be to completely perform some action with
no requirement to remember anything from that invocation to the next.

The method should probably also be self-contained.  By this I mean
that all information that the method needs to do its job should either
come from incoming parameters or from final static member variables (constants). 
The method probably should not depend on the values stored in non-final
static member variables, which are subject to change over time.

(A static method only has access to other static members
of the class, so it cannot depend on instance variables defined in the
class.)

An appropriate example of a static method is the sqrt method of
the Math class.  This method computes and “Returns the correctly
rounded positive square root of a double”
where the double value is
provided as a parameter to the method.  Each time the method is invoked,
it completes its task and doesn’t attempt to save any values from that
invocation to the next.  Furthermore, it gets all the information
that it needs to do its job from an incoming parameter.

Summary


Added complexity

The existence of static members tends to break up the simple OOP structures
that I have discussed in previous lessons in this miniseries.

While static members can be useful in some situations, the existence
of static members tends to complicate the overall object-oriented structure
of Java.

Furthermore, the overuse of static members can lead to problems similar
to those experienced in languages like C and C++ that support global variables
and global functions.

The class named Class

I discussed the class named Class and how a conceptual
object of type Class exists in memory following a reference to a
specific class in the program code.

The Class object represents the referenced class in memory, and
contains the static variables and static methods belonging to that class.
(It
contains some other information as well, such as the name of the superclass.)

Class members and instance members

Class variables and class methods are declared static (declaring
a member static in the class definition causes to be called a class member)
.

Instance variables and instance methods are not declared static.

Each object has its own copy …

Every object instantiated from a given class has its own copy of each
instance variable declared in the class definition.  (Instance
variables are not shared among objects.)

Every object instantiated from a given class acts like it has its own
copy of every instance method declared in the class definition.  (Although
instance methods are actually shared among objects in order to reduce the
amount of memory required, they are shared in such a way that they don’t
appear to be shared.)

Every object shares …

Every object instantiated from a given class shares the same single
copy of each class variable declared in the class definition.  Similarly,
every object instantiated from a given class shares the same copy of each
class method.

Accessing an instance member

An instance variable or an instance method can only be accessed by using
a reference to the object that owns it.  Even then, it may or may
not be accessible depending on the access modifier assigned by the programmer.

Accessing a class member

The single shared copy of a class variable or a class method can be
accessed in either of two ways:

  • Via a reference to any object instantiated from the class
  • By simply joining the name of the class to the name of the class variable
    or the class method

Again, the variable or method may or may not be accessible, depending on
the access modifiers assigned by the programmer.

When to use class variables

It is very often appropriate to use final static variables, as constants
in your programs.  It is rarely, if ever, appropriate to use non-final
static variables in your programs.  The use of non-final static variables
should definitely be minimized.

When to use static methods

It is often appropriate to use static methods in your programs, provided
there is no requirement for the method to remember anything from one invocation
to the next.  Static methods should be self-contained.

What’s Next?


The next lesson in this miniseries will address the special case of Array
Objects.

Complete Program Listing


A complete listing of the sample program is shown in Listing 13.

 

/*File MyClass01.java
Copyright 2002, R.G.Baldwin

This program illustrates static 
members of a class.  Output is:
  
Static variable
Mon Sep 17 09:52:27 CDT 2001

Instance variable
Mon Sep 17 09:52:32 CDT 2001
Static variable
Mon Sep 17 09:52:27 CDT 2001


Instance variable
Mon Sep 17 09:52:37 CDT 2001
Static variable
Mon Sep 17 09:52:27 CDT 2001
**************************************/
import java.util.Date;
class MyClass01{
  static Date v1 = new Date();
  Date v2 = new Date();

  public static void main(
                        String[] args){
    //Display static variable
    System.out.println(
                    "Static variable");
    System.out.println(MyClass01.v1);
    
    //Delay for five seconds
    try{
    Thread.currentThread().sleep(5000);
    }catch(InterruptedException e){}
    
    //Instantiate an object and 
    // display instance variable
    MyClass01 ref1 = new MyClass01();
    System.out.println();//blank line
    System.out.println(
                  "Instance variable");
    System.out.println(ref1.v2);
    
    //Now, display the static
    // variable using object reference
    System.out.println(
                    "Static variable");
    System.out.println(ref1.v1);
    
    System.out.println();//blank line
    
    //Delay for five seconds
    try{
    Thread.currentThread().sleep(5000);
    }catch(InterruptedException e){}
    
    //Instantiate another object 
    MyClass01 ref2 = new MyClass01();
    System.out.println();//blank line
    System.out.println(
                  "Instance variable");
    System.out.println(ref2.v2);
    
    //Now, display the same static
    // variable using object reference
    System.out.println(
                    "Static variable");
    System.out.println(ref2.v1);
  }//end main
}//end class MyClass01
//===================================//

Listing 13

About the author

Richard Baldwin
is a college professor (at Austin Community College in Austin, TX) and
private consultant whose primary focus is a combination of Java and XML.

Richard has participated in numerous consulting projects involving
Java, XML, or a combination of the two.  He frequently provides onsite
Java and/or XML training at the high-tech companies located in and around
Austin, Texas.  He is the author of Baldwin’s Java Programming Tutorials,
which has gained a worldwide following among experienced and aspiring Java
programmers. He has also published articles on Java Programming in Java
Pro magazine.

Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology
to real-world problems.

[email protected]

Latest Posts

Related Stories