<

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Introduction

In this article, we’ll explore the static keyword of the Java language in detail. We’ll find how we can apply keyword static to variables, methods, blocks, nested classes and what difference it makes.

2. The Anatomy of the static Keyword

In the Java programming language, the keyword static indicates that the particular member belongs to a type itself, rather than to an instance of that type.

This means that only one instance of that static member is created which is shared across all instances of the class.

The keyword can be applied to variables, methods, blocks and nested class.

3. The static Fields (or class variables)

In Java, if a field is declared static, then exactly a single copy of that field is created and shared among all instances of that class. It doesn’t matter how many times we initialize a class; there will always be only one copy of static field belonging to it. The value of this static field will be shared across all object of either same of any different class.

From the memory perspective, static variables go in a particular pool in JVM memory called Metaspace (before Java 8, this pool was called Permanent Generation or PermGen, which was completely removed and replaced with Metaspace).

3.1. Example of the static Field

Suppose we have a Car class with several attributes (instance variables). Whenever new objects are initialized from this Car blueprint, each new object will have its distinct copy of these instance variables.

However, suppose we are looking for a variable that holds the count of the number of Car objects that are initialized and is shared across all instances such that they can access it and increment it upon their initialization.

That’s where static variables come in:

public class Car {
    private String name;
    private String engine;
    
    public static int numberOfCars;
    
    public Car(String name, String engine) {
        this.name = name;
        this.engine = engine;
        numberOfCars++;
    }

    // getters and setters
}

Now for every object of this class that gets initialized, the same copy of the numberOfCars variable is incremented. So for this case, the following assertions will be true:

@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
    new Car("Jaguar", "V8");
    new Car("Bugatti", "W16");
 
    assertEquals(2, Car.numberOfCars);
}

3.2. Compelling Reasons to Use static Fields

  • When the value of variable is independent of objects
  • When the value is supposed to be shared across all objects

3.3. Key Points to Remember

  • Since static variables belong to a class, they can be accessed directly using class name and don’t need any object reference
  • static variables can only be declared at the class level
  • static fields can be accessed without object initialization
  • Although we can access static fields using an object reference (like ford.numberOfCars++) , we should refrain from using it as in this case it becomes difficult to figure whether it’s an instance variable or a class variable; instead, we should always refer to static variables using class name (for example, in this case, Car.numberOfCars++)

4. The static Methods (or Class Methods)

Similar to static fields, static methods also belong to a class instead of the object, and so they can be called without creating the object of the class in which they reside. They’re meant to be used without creating objects of the class.

4.1. Example of static Method

static methods are generally used to perform an operation that is not dependent upon instance creation.

If there is a code that is supposed to be shared across all instances of that class, then write that code in a static method:

public static void setNumberOfCars(int numberOfCars) {
    Car.numberOfCars = numberOfCars;
}

static methods are also widely used to create utility or helper classes so that they can be obtained without creating a new object of these classes.

Just take a look at Collections or Math utility classes from JDK, StringUtils from Apache or CollectionUtils from Spring framework and notice that all methods are static.

4.2. Compelling Reasons to Use static Methods

  • To access/manipulate static variables and other static methods that don’t depend upon objects
  • static methods are widely used in utility and helper classes

4.3. Key Points to Remember

  • static methods in Java are resolved at compile time. Since method overriding is part of Runtime Polymorphism, so static methods can’t be overridden
  • abstract methods can’t be static
  • static methods cannot use this or super keywords
  • The following combinations of the instance, class methods and variables are valid:
    1. Instance methods can directly access both instance methods and instance variables
    2. Instance methods can also access static variables and static methods directly
    3. static methods can access all static variables and other static methods
    4. static methods cannot access instance variables and instance methods directly; they need some object reference to do so

5. A static Block

A static block is used for initializing static variables. Although static variables can be initialized directly during declaration, there are situations when we’re required to do the multiline processing.

In such cases, static blocks come in handy.

If static variables require additional, multi-statement logic while initialization, then a static block can be used.

5.1. The static Block Example

Suppose we want to initialize a list object with some pre-defined values.

This becomes easy with static blocks:

public class StaticBlockDemo {
    public static List<String> ranks = new LinkedList<>();

    static {
        ranks.add("Lieutenant");
        ranks.add("Captain");
        ranks.add("Major");
    }
    
    static {
        ranks.add("Colonel");
        ranks.add("General");
    }
}

In this example, it wouldn’t be possible to initialize List object with all the initial values along with declaration; and that’s why we’ve utilized the static block here.

5.2. Compelling Reasons to Use static Blocks

  • If initialization of static variables requires some additional logic except the assignment
  • If the initialization of static variables is error-prone and requires exception handling

5.3. Key Points to Remember

  • A class can have multiple static blocks
  • static fields and static blocks are resolved and executed in the same order as they are present in the class

6. A static Class

Java programming language allows us to create a class within a class. It provides a compelling way of grouping elements that are only going to be used in one place, this helps to keep our code more organized and readable.

The nested class architecture is divided into two:

  • nested classes that are declared static are called static nested classes whereas,
  • nested classes that are non-static are called inner classes

The main difference between these two is that the inner classes have access to all member of the enclosing class (including private), whereas the static nested classes only have access to static members of the outer class.

In fact, static nested classes behaved exactly like any other top-level class but enclosed in the only class which will access it, to provide better packaging convenience.

6.1. Example of static Class

The most widely used approach to create singleton objects is through static nested class is it doesn’t require any synchronization and is easy to learn and implement:

public class Singleton  {    
    private Singleton() {}
    
    private static class SingletonHolder {    
        public static final Singleton instance = new Singleton();
    }    

    public static Singleton getInstance() {    
        return SingletonHolder.instance;    
    }    
}

6.2. Compelling Reasons to Use a static Inner Class

  • Grouping classes that will be used only in one place increases encapsulation
  • The code is brought closer to the place that will be only one to use it; this increases readability and code is more maintainable
  • If nested class doesn’t require any access to it’s enclosing class instance members, then it’s better to declare it as static because this way, it won’t be coupled to the outer class and hence will be more optimal as they won’t require any heap or stack memory

6.3. Key Points to Remember

  • static nested classes do not have access to any instance members of the enclosing outer class; it can only access them through an object’s reference
  • static nested classes can access all static members of the enclosing class, including private ones
  • Java programming specification doesn’t allow us to declare the top-level class as static; only classes within the classes (nested classes) can be made as static

7. Conclusion

In this article, we saw the static keyword in action. We also read about the reasons and advantages for using static fields, static methods, static blocks and static inner classes.

As always, we can find the complete code over on GitHub.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS

  Subscribe  
newest oldest most voted
Notify of
Cuneyt Caliskan
Guest
Cuneyt Caliskan

Hello and thanks for all the great guides that you are publishing, really appreciate the effort.
I would like to point out the example of static blocks where you mention that it wouldn’t be possible to initialize the static field along with the declaration whereas it is totally possible. An example as below works perfectly fine.

private static List static_list = new ArrayList() {
{
add(“XXX”);
add(“YYY”);
}
};

Cheers

Grzegorz Piwowarek
Editor

Well, yes and no – in this case, you’re actually subclassing the ArrayList and adding a custom initializer block there – which is considered an anti-pattern in most cases