Working with Statics

Astatic method is a method that isn't associated with an instance of a class. (Unless you jumped straight to this chapter, you already knew that.) Instead, the method belongs to the class itself. As a result, you can call the method without first creating a class instance. In this chapter, you find out everything you need to know about creating and using static fields and methods.

Understanding Static Fields and Methods

According to my handy Webster's dictionary, the word static has several different meanings. Most of them relate to the idea of being stationary or unchanging. For example, a static display is a display that doesn't move. Static electricity is an electrical charge that doesn't flow. A static design is a design that doesn't change.

The term static as used by Java doesn't mean unchanging. For example, you can create a static field, and then assign values to it as a program executes. Thus the value of the static field can change.

To further confuse things, the word static can also mean interference, as in radio static that prevents you from hearing music clearly on the radio. But in Java, the term static doesn't have anything to do with interference or bad reception.

So what does the term static mean in Java? It's used to describe a special type of field or method that isn't associated with a particular instance of a class. Instead, static fields and methods are associated with the class itself. That means you don't have to create an instance of the class to access a static field or methods. Instead, you access a static field or method by specifying the class name, not a variable that references an object.

Static fields and methods have many common uses. Here are but a few:

Working with Static Fields

A static field is a field that's declared with the static keyword, like this:

private static int ballCount;

Note that the position of the static keyword is interchangeable with that of the visibility keywords (private and public, as well as protected, which I describe in the next chapter). As a result, the following statement works as well:

static private int ballCount;

As a convention, most programmers tend to put the visibility keyword first.

  Tip 

Note that you can't use the static keyword within a class method. Thus the following code won't compile:

static private void someMethod() { static int x; }

In other words, fields can be static, but local variables can't.

You can provide an initial value for a static field; here's an example:

private static String district = "Northwest";

Static fields are created and initialized when the class is first loaded. That happens when a static member of the class is referred to or when an instance of the class is created, whichever comes first.

Another way to initialize a static field is to use a static initializer, which I cover later in this chapter, in the section "Using Static Initializers."

Using Static Methods

A static method is a method declared with the static keyword. Like static fields, static methods are associated with the class itself, not with any particular object created from the class. As a result, you don't have to create an object from a class before you can use static methods defined by the class.

The best-known static method is main, which is called by the Java runtime to start an application. The main method must be static-which means applications are run in a static context by default.

One of the basic rules of working with static methods is that you can't access a non-static method or field from a static method. That's because the static method doesn't have an instance of the class to use to reference instance methods or fields. For example, the following code won't compile:

public class TestClass { private int x = 5; // an instance field public static void main(String[] args) { int y = x; // error: won't compile } }

Here the main method is static, so it can't access the instance variable x.

  Note 

However, you can access static methods and fields from an instance method. For example, the following code works fine:

public class Invoice { private static double taxRate = 0.75; private double salesTotal; public double getTax() { return salesTotal * taxRate; } }

Here the instance method named salesTotal has no trouble accessing the static field taxRate.

Counting Instances

One common use for static variables is to keep track of how many instances of a class have been created. To illustrate how you can do this, consider the program in Listing 3-1. This program includes two classes. The CountTest class is a simple class that keeps track of how many times its constructor has been called. Then the CountTestApp class uses a for loop to create ten instances of the class, displaying the number of instances that have been created after it creates each instance.

Note that the instance count in this application is reset to zero each time the application is run. As a result, it doesn't keep track of how many instances of the CountTest class have ever been created-only of how many have been created during a particular execution of the program.

Listing 3-1: The CountTest Application

public class CountTestApp → 1 { public static void main(String[] args) { printCount(); for (int i = 0; i < 10; i++) { CountTest c1 = new CountTest(); → 8 printCount(); → 9 } } private static void printCount() { System.out.println("There are now " → 15 + CountTest.getInstanceCount() + " instances of the CountTest class."); } } class CountTest → 21 { private static int instanceCount = 0; → 23 public CountTest() → 25 { instanceCount++; } public static int getInstanceCount() → 29 { return instanceCount; } }

The following paragraphs describe some of the highlights of this program:

1

The start of the CountTestApp class, which tests the CountTest class.

8

Creates an instance of the CountTest class. Because this code is contained in a for loop, a total of ten instances are created.

9

Calls the printCount method, which prints the number of CountTest objects that have been created so far.

15

This line prints a message indicating how many CountTest objects have been created so far. It calls the static getInstanceCount method of the CountTest class to get the instance count.

21

The start of the CountTest class.

23

The static instanceCount variable, which stores the instance count.

25

The constructor for the CountTest class. Notice that the instanceCount variable is incremented within the constructor. That way, each time a new instance of the class is created, the instance count is incremented.

29

The static getInstanceCount method, which simply returns the value of the static instanceCount field.

Open table as spreadsheet

  DESIGN PATTERN 

The Singleton pattern

A singleton is a class that you can use to create only one instance. When you try to create an instance, the class first checks to see if an instance already exists. If so, the existing instance is used. If not, a new instance is created.

You can't achieve this effect by using Java constructors, because a class instance has already been created by the time the constructor is executed. (That's why you can use the this keyword from within a constructor.) As a result, the normal way to implement a singleton class is to declare all the constructors for the class as private. That way, the constructors aren't available to other classes. Then you provide a static method that returns an instance. This method either creates a new instance or returns an existing instance.

Here's a bare-bones example of a singleton class:

class SingletonClass { private static SingletonClass instance; private SingletonClass() { } public static SingletonClass getInstance() { if (instance == null) instance = new SingletonClass(); return instance; } }

Here the SingletonClass contains a private instance variable that maintains a reference to an instance of the class. Then a default constructor is declared with private visibility to prevent the constructor from being used outside of the class. Finally, the static getInstance method calls the constructor to create an instance if the instance variable is null. Then, it returns the instance to the caller.

Here's a bit of code that calls the getInstance method twice, and then compares the resulting objects:

SingletonClass s1 = SingletonClass.getInstance(); SingletonClass s2 = SingletonClass.getInstance(); if (s1 == s2) System.out.println("The objects are the same"); else System.out.println("The objects are not the same");

When this code is run, the first call to getInstance creates a new instance of the SingletonClass class. The second call to getInstance simply returns a reference to the instance that was created in the first call. As a result, the comparison in the if statement is true, and the first message is printed to the console.

Preventing Instances

Sometimes you want to create a class that can't be instantiated at all. Such a class consists entirely of static fields and methods. A good example in the Java API is the Math class. Its methods provide utility-type functions that aren't really associated with a particular object. You may occasionally find the need to create similar classes yourself. For example, you might create a class with static methods for validating input data. Or you might create a database access class that has static methods to retrieve data from a database. You don't need to create instances of either of these classes.

You can use a simple trick to prevent anyone from instantiating a class. To create a class instance, you have to have at least one public constructor.

If you don't provide a constructor in your class, Java automatically inserts a default constructor, which happens to be public.

All you have to do to prevent a class instance from being created, then, is to provide a single private constructor-like this:

public class Validation { private Validation() {} // prevents instances // static methods and fields go here }

Now, because the constructor is private, the class can't be instantiated.

  TECHNICAL STAUFF 

Incidentally, the Math class uses this technique to prevent you from creating instances from it. Here's an actual snippet of code from the Math class:

public final class Math { /** * Don't let anyone instantiate this class. */ private Math() {}

I figure if this trick is good enough for the folks who wrote the Math class, it's good enough for me.

Using Static Initializers

In the previous chapter, you discover initializer blocks that you can use to initialize instance variables. Initializer blocks aren't executed until an instance of a class is created, so you can't count on them to initialize static fields. After all, you might access a static field before you create an instance of a class.

Java provides a feature called a static initializer that's designed specifically to let you initialize static fields. The general form of a static initializer looks like this:

static { statements... }

As you can see, a static initializer is similar to an initializer block, but begins with the word static. As with an initializer block, you code static initializers in the class body but outside of any other block, such as the body of a method or constructor.

The first time you access a static member such as a static field or a static method, any static initializers in the class are executed-provided you haven't already created an instance of the class. That's because the static initializers are also executed the first time you create an instance. In that case, the static initializers are executed before the constructor is executed.

  Tip 

If a class has more than one static initializer, they're executed in the order in which they appear in the program.

Here's an example of a class that contains a static initializer:

class StaticInit { public static int x; static { x = 32; } // other class members such as constructors and // methods go here... }

This example is pretty trivial. In fact, you can achieve the same effect just by assigning the value 32 to the variable when it is declared. If, however, you had to perform a complicated calculation to determine the value of x-or if its value comes from a database-a static initializer could be very useful.

Категории