Mr. Happy Object teaches static methods
When to choose static methods over instance methods
November 21, 2001
Q: When would you create static methods as opposed to instance methods? I understand that static methods allow you to use those methods without having to create an instance of that class, and that class methods apply to the class rather than an object. Are these the only reasons? Could you give an example of a case where you would use a class method over an instance method?
A: Note: You can download the source code that accompanies this article from Resources .
Consider the following class definition:
public class MrHappyObject {
private String _mood = _HAPPY;
private final static String _HAPPY = "happy";
private final static String _ANNOYED = "annoyed";
private final static String _ANGRY = "angry";
public void printMood() {
System.out.println( "I am " + _mood );
}
public void receivePinch() {
if( _mood.equals( _HAPPY ) ) {
_mood = _ANNOYED;
} else {
_mood = _ANGRY;
}
}
public void receiveHug() {
if( _mood.equals( _ANGRY ) ) {
_mood = _ANNOYED;
} else {
_mood = _HAPPY;
}
}
}
First, before I get emails about it, there are more object-oriented ways to track and transition between states. However, those fancy ways would detract from the intent of the example. Now, without further ado…
printMood()
, receivePinch()
, and receiveHug()
are all instance methods. Syntactically, you call these methods instance methods because they are not static; but the important distinction concerns why I didn’t declare them as static.
Instance methods are instance methods because they rely on the state of the specific object instance. Instance methods are tied to a particular instance because the behavior that the method invokes relies upon the state of that particular instance.
Consider the following example:
MrHappyObject obj1 = new MrHappyObject();
MrHappyObject obj2 = new MrHappyObject();
obj1.printMood();
obj2.printMood();
When obj1
and obj2
first instantiate, they have the same state — they are born happy. As a result, when the printMood()
is called on each instance, each object prints "I am happy"
to the screen. However, every object instance has its own state that can vary independently of all other instances of that class of object.
As obj1
and obj2
go through their day, their states can vary independently from one another. Here I hug obj1
and pinch obj2
:
obj1.receiveHug();
obj2.receivePinch();
obj1.printMood();
obj2.printMood();
Now when I query each instance’s mood, obj1
is happy while obj2
is annoyed. While the example is silly, it drives home a point: Every instance possesses its own state, and that state is independent of every other object. Any method whose behavior depends upon the particular state of a particular instance is an instance method. You should not declare such a method as static.
When you declare a method as static, you define that method as being a class method. A class method applies to the class as opposed to any particular instance. The behavior instigated by a class method does not rely on the state of a particular instance. In fact, a static method cannot rely on an instance’s state since static methods lack access to this reference. Instead, the behavior of a class method either depends on a state that all objects share at the class level, or is independent of any state at all.
Let’s add the following definitions to the original MrHappyObject
:
private static int _instantiations;
public MrHappyObject() {
_instantiations++;
}
public static int instances() {
return _instantiations;
}
instances()
is a static method. The instances()
method returns the number of MrHappyObjects
that have been created. The number of instantiations is independent of any particular MrHappyObject
. Instead, MrHappyObject
tracks the number of instantiations at the class level.
Again, this example is a bit contrived but it demonstrates an important lesson: Class methods instigate behavior that is independent of instance state. instances()
returns the number of instances regardless of whether obj1
is happy and obj2
is annoyed. The instance state is simply irrelevant. Any method that is independent of instance state is a candidate for being declared as static.
Note that I say “candidate for being declared as static.” Even in the previous example nothing forces you to declare instances()
as static. Declaring it as static just makes it more convenient to call since you do not need an instance to call the method. Sometimes you will have methods that don’t seem to rely on instance state. You might not want to make these methods static. In fact you’ll probably only want to declare them as static if you need to access them without an instance.
Moreover, even though you can declare such a method as static, you might not want to because of the inheritance issues that it interjects into your design. Take a look at “Effective Object-Oriented Design” to see some of the issues that you will face.
Anyway, simply counting the number of instantiations is a fairly useless example — it’s probably not something you will do in your day-to-day coding. However, sometimes you will want to use statics.
Static methods prove useful for creating utility classes and factory methods. (See “Factory Methods” for more information.)
A utility class simply contains static methods and no public constructor. Utility classes are not meant to be instantiated. As Joshua Bloch points out in Effective Java Programming Language Guide, utility classes have earned a bad reputation because they are easily abused and can lead to procedural programming.
However, utility classes do have valid uses. Take a look at java.lang.Math
, java.util.Arrays
, and java.util.Collections
; each is a utility class. These utilities group related methods on primitive values, arrays, and interfaces. These related methods are placed in these utility classes since they cannot go anywhere else (you can’t place methods into a primitive, array, or interface after all!).
Utility classes have another use. Sometimes you cannot extend a class because it is declared final. Utility classes are an excellent place to put methods that you would have otherwise put into a subclass.