Static: What, why, and how?
Prerequisite knowledge: Basic object orientation (especially the this
keyword), basic Java. I will be compiling and running the Java from the command
line, code examples that start with a dollar sign $
are lines executed from
the command line from the directory that the code resides.
So you've been programming for a little while now, maybe you're programming in Java and you've been noticing this "static" word lying around. What does it mean?
Let's say we have this code:
public class Application {
public static void main(String[] args) {
Application.sayHello();
}
public static void sayHello() {
System.out.println("Hello, world!");
}
}
Compile and run:
$ javac Application.java
$ java Application
Output:
Hello, world!
You've seen the method signature public static void main
before. It has a
special meaning in Java (and lots of other languages) as the entry point of the
program. The sayHello()
method is new, though. Notice how we call the method
by using the class name in front of it, Application.sayHello()
. This is
because the formal definition of a static method is:
A method that does not require access, nor can modifiy an instance of the class it belongs to.
Because the method does not require any knowledge of instances of the class, it should be called from the class itself. It is possible to call static methods from objects of the class, but it isn't good practice. This code, for example, compiles and runs fine:
public class Application {
public static void main(String[] args) {
Application a = new Application();
a.sayHello();
}
public static void sayHello() {
System.out.println("Hello, world!");
}
}
Compile and run:
$ javac Application.java
$ java Application
Output:
Hello, world!
However, it isn't clear that you're calling a static method in this code, thus it is considered bad practice.
Conversely, static methods do not have access to instances of the class they
belong to. For example, using the this
keyword or attempting to call a
non-static method from a static method will raise an error:
public class Application {
public int greets = 0;
public static void main(String[] args) {
this.greet();
}
public void greet() {
System.out.println("Hi there!");
greets++;
}
}
Compile:
$ javac Application.java
Compile error:
Application.java:5: non-static variable this cannot be referenced from a static context
this.greet();
^
1 error
The main
method is static and cannot refer to non-static methods of the
class. The use of the this
keyword in a static context doesn't make any sense
because static methods aren't part of any instance of the class, they are a
part of the class itself. this
simply does not exist in static methods.
Static methods are often referred to as class methods and non-static methods are called instance methods. If you hear anyone talking about class methods or variables, you could substitute class for static and it would be the same thing.
# The Static Usecase
So we've had an explanation of static and we've seen a few contrived examples but what about a real example? Where are static methods used in the real world?
The most prominent example I can think of is in the
Singleton design pattern.
The Singleton
design pattern is used to restrict the amount of objects of a
class to one. With static methods, this is an easy task:
public class Application {
private static Application singleton = null;
public static Application getInstance() {
if (singleton == null) {
singleton = new Application();
}
return singleton;
}
private Application() {
// intentionally empty, declared private
}
}
The class contains one static variable that is a reference to an instance of
itself and it has a method that creates that instance if it does not exist
and then returns it. No matter how many times you call the
Application.getInstance()
method, it will always return the same instance
of the class, and because the constructor is private you cannot create
instances of the class outside of the class.
Here's an example that proves the method returns the same instance of the
Application
class every time:
import java.util.Random;
public class Application {
private static Application singleton = null;
public static Application getInstance() {
if (singleton == null) {
singleton = new Application();
}
return singleton;
}
public int seed = 0;
private Application() {
Random rand = new Random();
this.seed = rand.nextInt();
}
public static void main(String[] args) {
Application app = Application.getInstance();
System.out.println(app.seed);
app = Application.getInstance();
System.out.println(app.seed);
app = Application.getInstance();
System.out.println(app.seed);
}
}
The top part of the code example is the same as the previous example with a
slight change to the constructor. The constructor now generates a random number
and assigns the instance variable seed
to that random number.
The main
method then gets an instance of the Application
class and prints
out the contents of the seed. It does this three times to prove that the seed
is the same every time. Here's the output:
1180384142
1180384142
1180384142
Your output will vary but the point is that the same number is printed out
three times. This signifies that the same instance of the Application
class
is being returned from Application.getInstance();
each time.
# The Singleton Usecase
I've said that static methods and variables are used with the Singleton pattern, but where is the Singleton pattern used?
The most common use for the Singleton pattern that I have seen is configuration
files. For example, ThinkUp uses the Singleton pattern for its Config
class,
which can be found here.
The Config
class reads a configuration file in the code base and then stores
all of the options in an array made available in a singleton object. This makes
the configuration options available globally to the application and stops
developers creating multiple instances of the Config class and potentially
causing problems when the configuration is modified on the fly.