Bits of Java – Episode 14: The static keyword

In this episode we will discuss the meaning of the static keyword and we will see where it can be used in your code.

There are various places in your code when you can use the static keyword. Let’s see them.

  • static fields: when you mark a variable as static you are creating a class variable, meaning that the variable is shared among all the instances of the class in which is defined. This is in contrast with instance variables, which are non-static variables defined within a class, and of which every instance of the class gains its own copy.

public class MyClass {
  public static int counter = 0; //this is a class (static) variable
  public int number; //this is an instance (non-static) variable

  public static void main(String[] args) {
      MyClass instance1 = new MyClass();
      instance1.counter = 1;
      instance1.number = 30;

      MyClass instance2 = new MyClass();
      instance2.counter = 2;
      instance2.number = 40;

      /*
      * Both these statement will print 2, because counter is a class variable, 
      * meaning each instance share the same variable
      */
      System.out.println(instance1.counter);
      System.out.println(instance2.counter);

      /*
      * The first statement will print 30 and the second 40. number is an 
      * instance variable, meaning every instance of the class gets its own
      * number variable and modify such variable for one instance does not
      * affect the value for the other instance
      */
      System.out.println(instance1.number);
      System.out.println(instance2.number);
  }
}

Since static variables are shared among all the instances, we actually do not need any instance to call them. We just need the class to be loaded, and that`s it!


public class MyClass {
  public static int counter = 0; //this is a class (static) variable

  public static void main(String[] args) {

      //We do not need any instance of the class to call a static variable!
      System.out.println(MyClass.counter);
  }
}

This is probably the most common way to access a static variable. What you may not know (I did not, at least) is that you can also do something like this:


public class MyClass {
  public static int counter = 0; //this is a class (static) variable

  public static void main(String[] args) {
      MyClass instance1 = new MyClass();
      System.out.println(instance1.counter); //prints 0

      instance1 = null;
      System.out.println(instance1.counter); //still prints 0
  }
}

Here we are setting the instance of MyClass to null, but accessing a static variable through a null instance is still possible and does not throw any runtime Exception. This is because, being a class variable, it exists and it is accessible also if the instance is null as long as the class is loaded!

  • static initializer blocks: static variables can be initialized in the same statement where they are declared, in an instance initializer block or in a static initializer block. If the static variable is also marked as final instead, it can only be initialized in the same statement of the declaration or in a static initializer block, and cannot be initialized more than once.

public class MyClass {
  public static int counter = 0; //this is a class (static) variable
  public static final int NUMBER = 0; //this is a class (static) final variable
  public static final int NUMBER2; //this is a class (static) final variable
  public static final int NUMBER3; //this is a class (static) final variable

  //This is an instance initializer block
  {
      counter = 2; //ALLOWED

      /*
      * DOES NOT COMPILE, static final variables cannot be initialized
      * in an instance initializer block
      */
      NUMBER2 = 3;
  }

  //This is a static initializer block
  static {
      counter = 3; //ALLOWED

      NUMBER3 = 5; //ALLOWED

      /*
      * DOES NOT COMPILE, final variable cannot be initialized
      * more than once
      */
      NUMBER = 4;
  }
 }

  • static methods: the static keyword can be also applied to a method, with the exception of abstract methods. This is because abstract methods, by definition, need to be overridden, while, static methods cannot be overridden. Thus, the two keywords, static and abstract are conflicting with each other and cannot be used together.

    That said, a static method, as we anticipated, is a method that cannot be overridden by any subclass of the class in which it is defined, but it can only be hidden. I will not discuss here what these two terms, overriding and hiding, mean, because this will be the topics of the next two weeks, so if you are not familiar with these concepts, be patient, please!

    As for a static variable, a static method can be called without the need of instantiate the class before. This is exactly the reason why the main method is static. The JVM can call it directly by MyClass.main(), so without creating an instance of MyClass.


public class MyClass {
  public static void saySomething() {
      System.out.println("Something");
  }

  public static void main(String[] args) {

      MyClass.saySomething(); //no need to create an instance of the class

      new MyClass().saySomething(); //but you can also do that
  }
}

  • static imports: as the standard imports allow you to import classes written by others and use them in your code, the static import allows you to import static class members into your code and use them. Of course, the standard rules for visibility apply, namely if a static method is marked as private there is no way we can access it from another class.

    Let’s say MyClass of the previous example is defined in package mypackage.A and we want to use its static method from another class in another package.


package mypackage.B

import static mypackage.A.MyClass.saySomething;

public class AnotherClass {

  public static void main(String[] args) {
      /*
      * This will work because we have imported it, so we do not 
      * need to put the name of the class before
      */
      saySomething(); 

      /*
      * DOES NOT COMPILE, because we are not importing MyClass, so the 
      * compiler does not know what it is. If we wanted to use that
      * we would need to add "import mypackage.A.MyClass"
      */
      MyClass.saySomething();
  }
}

​ The naming conventions for static imports are the same as the ones for standard import and the same rules apply for the allowed names (only letters, $, _, . and numbers are allowed; is not possible to start a package name with a number nor a . and a single _ is not allowed).

I hope the discussion on the static keyword was helpful. Next week, as anticipated, we will discuss the concept of method overriding and we will compare that to the one of method overloading!

by Ilenia Salvadori