While teaching Intertech’s Complete Java Training, one student asked me why he was seeing the following warning in Eclipse: “The static method sayHello from the type HelloWorld should be accessed in a static way.”

The warning (not an error.. . this would compile and run) was due to a call to a static method via an object reference – (line 8 below):

public class HelloWorld {
	public static void sayHello() {
		System.out.println("Hello!");
	}

	public static void main(String[] args) {
	    HelloWorld hw = new HelloWorld();
	    hw.sayHello();
	}
}

Another student suggested that it was just a “style” warning, due to a naming convention used in Java, where static methods are accessed via the class name, rather than an object reference:

public static void main(String[] args) {
    HelloWorld.sayHello();
}

In large part, this explanation was correct: it is the typical convention to use a class name to access a static variable, and that’s what the warning was referring to.  Using the class name helps clarify to one reading this code that the class, rather than the instance is being sent a message. However, there is another reason for this convention that goes beyond clarity and aesthetics.  This warning is in place to help avoid a potential coding error.

Let’s create another simple example, but one that uses inheritance (Parent and Child).  In the Parent we’ll create an instance method called sayHello(), and in the Child we’ll override that method.

public class Parent {
	public void sayHello() {
		System.out.println("Hello from the Parent.");
	}
}
public class Child extends Parent {
	public void sayHello() {
		System.out.println("Hello from the Child.");
	}
}

When lines 3 & 6 are executed below, “Hello from the Child” is displayed both times, due to the “dynamic method binding” that takes place with polymorphism.  In other words, an instance method is chosen based on the runtime type of the object, not the type of the object reference.

public static void main(String[] args) {
	Child c = new Child();
	c.sayHello(); // prints out "Hello from the Child."

	Parent p = new Child();
	p.sayHello(); // prints out "Hello from the Child."
}

What happens if we modify the methods to be static?

public class Parent {
	public static void sayHello() {
		System.out.println("Hello from the Parent.");
	}
}
public class Child extends Parent {
	public static void sayHello() {
		System.out.println("Hello from the Child.");
	}
}

The behavior changes: the object reference type, as opposed to the runtime object type, is used to invoke a static method.  In other words, static methods are not invoked dynamically in the same way instance methods are.  This is known as “static binding.” Therefore, lines 3 & 6 below now display different messages:

public static void main(String[] args) {
	Child c = new Child();
	c.sayHello(); // prints out "Hello from the Child."

	Parent p = new Child();
	p.sayHello(); // prints out "Hello from the Parent."
}

When this happens, it’s often a mistake: the developer was likely thinking polymorphism would kick in for line 6, and the Child, rather than the Parent’s sayHello would be invoked. Since it’s a source of a potential error, it’s a good coding practice to use the class name when invoking a static method.  This is what is meant with the warning, “a static method (sayHello) should be accessed in a static way (via the class name Parent or Child).”  This convention helps reduce the chance that we’ve made a coding mistake and it helps clarify that a class method is being called to those who subsequently read our code.

public static void main(String[] args) {
	Child.sayHello(); // prints out "Hello from the Child."

	Parent.sayHello(); // prints out "Hello from the Parent."
}