Java SE: static modifier

Java Fundamentals

javase
static
What is the static modifier in Java
Author

albertprofe

Published

Tuesday, June 1, 2021

Modified

Tuesday, November 12, 2024

📘 static modifier

In Java, the static modifier is used to indicate that a class or class member belongs to the class itself, rather than to an instance of the class.

In other words, the static modifier indicates that the class or class member is associated with the class as a whole, rather than with a specific instance of the class.


1 static modifier

Classical use and basic example of static method, we call within the class our static method just using the name of the method printArea():

Two static methods with parameters. Parameters are the variables we use in the method definition whereas arguments are the values we pass in the method call. These two terms are often used interchangeably

Two static methods with parameters. Parameters are the variables we use in the method definition whereas arguments are the values we pass in the method call. These two terms are often used interchangeably

The static modifier has several different uses in Java, depending on where it is applied. Here are some examples of how the static modifier can be used in Java.

1.1 static code block

In Java, we have a special block known as aStatic Initialization Block. A Static Initialization Block is executed before the main() method, it will execute once. This block will not return anything and we can not use the this keyword since it does not have any instance.

For example:

MovieManager.java
static {            
    int count = 0;
    String name ="Alien";
    double priceMovie = 45.50;
};

1.2 static field

When applied to a field, the static modifier indicates that the field belongs to the class itself, rather than to an instance of the class. This means that all instances of the class share the same value for the static field.

For example:

Counter.java
public class Counter {
    // Static field
    private static int count = 0;

    // Constructor
    public Counter() {
        count++;
    }

    // Getter method for the count field
    public static int getCount() {
        return count;
    }
}

In this example, the count field is marked as static, which means that all instances of the Counter class share the same value for the count field. When a new instance of the Counter class is created, the count field is incremented, and the new value is shared by all instances of the class.

Another example:

Account.java
public class Account {
    // Static field
    private static int nextAccountNumber = 1;

    // Private instance variables
    private int accountNumber;
    private String name;
    private double balance;

    // Constructor
    public Account(String name, double balance) {
        this.accountNumber = nextAccountNumber++;
        this.name = name;
        this.balance = balance;
    }

    // Getter method for the accountNumber field
    public int getAccountNumber() {
        return accountNumber;
    }

    // Getter method for the name field
    public String getName() {
        return name;
    }

    // Getter method for the balance field
    public double getBalance() {
        return balance;
    }

    // Method for depositing money into the account
    public void deposit(double amount) {
        balance += amount;
    }

    // Method for withdrawing money from the account
    public void withdraw(double amount) {
        balance -= amount;
    }
}

In this example, the Account class defines a nextAccountNumber field that is marked as static. This means that the nextAccountNumber field belongs to the Account class itself, rather than to an instance of the Account class. This means that all instances of the Account class share the same value for the nextAccountNumber field.

When a new instance of the Account class is created, the nextAccountNumber field is incremented, and the new value is shared by all instances of the class. This allows each instance of the Account class to have a unique accountNumber field, which is generated automatically using the nextAccountNumber field.

1.3 static method

When applied to a method, the static modifier indicates that the method belongs to the class itself, rather than to an instance of the class. This means that the static method can be called on the class itself, rather than on an instance of the class.

For example:

MathUtils.java
public class MathUtils {
    // Static method
    public static double squareRoot(double number) {
        return Math.sqrt(number);
    }
}

In this example, the squareRoot() method is marked as static, which means that it can be called on the MathUtils class itself, rather than on an instance of the MathUtils class. This allows the squareRoot() method to be called without creating an instance of the MathUtils class, which can be useful in some situations.

For example:

MovieManager.java
public class MovieManager {

    // Static method
    public static boolean createMovie(Movie movie) {
        boolean result = false;
        // to-do algorithmic to solve this method
        return result;
    }

    // Static method
    public static boolean deleteMovie(String idMovie) {
        boolean result = false;
        // to-do algorithmic to solve this method
        return result;
    }

    // Static method
    public static boolean updateMovie(Movie movie) {
        boolean result = false;
        // to-do algorithmic to solve this method
        return result;
    }

    // Static method
    public static List<Movie> getAllMovies() {
        List<Movie> movies = new ArrayList<>();
        // to-do algorithmic to solve this method
        return movies;
    }

    // Static method
    public static List<Movie> findMovie(String title) {
        List<Movie> movies = new ArrayList<>();
        // to-do algorithmic to solve this method
        return movies;
    }
    
}

classDiagram
  class Movie {
    -title: String
    -reviews: List<Review>
    -director: Director
  }
  
  class Critic {
    -publications: int
  }
  
  class Director {
    -oscars: int
  }
  class Review {
    -rating: int
    -comment: String
    -critic: Critic
  }
  class Person {
    -name: String
  }
  
  class MovieManager {
    -static boolean deleteMovie(id)$
    -static boolean createMovie(id)$
    -static boolean updateMovie(id)$
    -getAllMovies()$ List~Movie~
    -findMovie(id)$ List~Movie
  }

  MovieManager -- Movie
  Movie *-- Review
  Movie *-- Director
  Review o-- Critic
  Person <-- Director
  Person <-- Critic

1.4 static class

When applied to a class, the static modifier indicates that the class is a nested class. In other words, the static class is defined inside another class, and is associated with the outer class.

Account.java
public class Account {
    // Static field
    private static int nextAccountNumber = 1;

    // Private instance variables
    private int accountNumber;
    private String name;
    private double balance;

    // Static nested class
    public static class Transaction {
        // Private instance variables
        private int transactionNumber;
        private double amount;
        private String type;

        // Constructor
        public Transaction(double amount, String type) {
            this.transactionNumber = nextAccountNumber++;
            this.amount = amount;
            this.type = type;
        }

        // Getter method for the transactionNumber field
        public int getTransactionNumber() {
            return transactionNumber;
        }

        // Getter method for the amount field
        public double getAmount() {
            return amount;
        }

        // Getter method for the type field
        public String getType() {
            return type;
        }
    }

    // Constructor
    public Account(String name, double balance) {
        this.accountNumber = nextAccountNumber++;
        this.name = name;
        this.balance = balance;
    }

    // Getter method for the accountNumber field
    public int getAccountNumber() {
        return accountNumber;
    }

    // Getter method for the name field
    public String getName() {
        return name;
    }

    // Getter method for the balance field
    public double getBalance() {
        return balance;
    }

}

Here is an example of how the static modifier can be used when applied to a class in Java, using an Account class and a nested Transaction class as examples:

2 static scope

In Java SE (Standard Edition), the term “static scope” typically refers to the visibility and accessibility of variables and methods marked with the static keyword within a class or interface.

When a variable or method is declared as static within a class or interface, it means that it belongs to the class itself rather than to instances of the class. This has implications for how these members are accessed:

  • Visibility within the class: Static variables and methods can be accessed directly within other static methods or variables of the same class without needing an instance of the class.

  • Access from outside the class: Static variables and methods can also be accessed directly using the class name, without needing an instance of the class. This access can occur from other classes, as long as the static member is declared with appropriate access modifiers (e.g., public, protected, or private).

  • Lifetime: Static variables exist for the entire duration of the program’s execution, and there is only one instance of each static variable per class, shared by all instances of the class.

  • Initialization: Static variables are initialized only once, at the start of the program execution, before any instances of the class are created.

Here’s a basic example to illustrate static scope:

Account.java
public class MyClass {
    // Static variable
    public static int staticVariable = 10;
    
    // Instance variable
    public int instanceVariable;
    
    // Static method
    public static void staticMethod() {
        System.out.println("This is a static method.");
        // Can access static variables directly
        System.out.println("Static variable: " + staticVariable);
        // Cannot access instance variables directly
        // System.out.println("Instance variable: " + instanceVariable); // This line would cause a compilation error
    }
    
    // Instance method
    public void instanceMethod() {
        System.out.println("This is an instance method.");
        // Can access both static and instance variables directly
        System.out.println("Static variable: " + staticVariable);
        System.out.println("Instance variable: " + instanceVariable);
    }
}

In this example, staticVariable is a static variable that can be accessed directly within both staticMethod() and instanceMethod(), while instanceVariable is an instance variable that can only be accessed within instanceMethod() or other instance methods, requiring an instance of MyClass.

3 static vs. non-static

3.0.1 Pros & cons usage static methods

Pros of making a method static Cons of making a method static
Can be called directly on the class, without needing to create an instance Cannot access non-static fields and methods of the class
Can be used as utility methods that don’t depend on the state of an object Can only work with the parameters passed to it and not use information unique to each object or instance
Can be used to access only static variables and methods, making it more efficient Can be challenging to make sure all instances of a class are modified consistently when using static methods

3.0.2 Pros & cons usage non-static methods

Pros of making a method non-static Cons of making a method non-static
Can access both static and non-static fields and methods of the class, allowing it to use the state of an object to determine its behavior Can only be called on an instance of the class, so you need to create an object of a class before using the method
Are associated with an instance of the class, so they can use the information that is unique to each object Can cause confusion when working with non-static methods because it could be called on different instances, which could cause unexpected behavior
Object-oriented design principles promote the use of non-static methods because they can be overridden by subclasses to change their behavior

4 final modifier

The final modifier in Java is a powerful keyword used to restrict the modification of variables, methods, and classes.

The final modifier in Java is a powerful keyword used to restrict the modification of variables, methods, and classes. Here’s an overview of how it works:

Final Variables

When applied to variables, the final modifier creates constants that cannot be reassigned once initialized.

  • For primitive types, the value cannot be changed.
  • For reference types, the reference cannot be changed, but the object’s contents can still be modified.
final int MAX_VALUE = 100;
final List<String> names = new ArrayList<>();

// Valid: Modifying the list's contents
names.add("Alice");

// Invalid: Attempting to reassign the variable
// MAX_VALUE = 200; // Compilation error
// names = new ArrayList<>(); // Compilation error

Final Methods

A final method cannot be overridden by subclasses. This is useful for preserving critical functionality or preventing unexpected behavior in inherited classes.

class Parent {
    final void display() {
        System.out.println("This method cannot be overridden");
    }
}

class Child extends Parent {
    // Invalid: Attempting to override a final method
    // void display() { } // Compilation error
}

Final Classes

A final class cannot be extended or inherited. This is often used to create immutable classes or to prevent unintended modifications to a class’s behavior.

final class ImmutableClass {
    // Class implementation
}

// Invalid: Attempting to extend a final class
// class Subclass extends ImmutableClass { } // Compilation error

4.1 Key Points

  1. Final variables must be initialized either at declaration or in the constructor.
  2. Static final variables are often used to define constants.
  3. Final methods in interfaces are redundant, as interface methods are implicitly final.
  4. The final keyword can improve performance in some cases, as the compiler can optimize final methods and variables.

5 static / final

Modifier Use Case Description Example
static Class members Belongs to the class rather than instances public static int count = 0;
static Utility methods Methods that don’t require instance state public static int add(int a, int b) { return a + b; }
static Constants Class-level constants (usually combined with final) public static final double PI = 3.14159;
static Static blocks Code executed when class is loaded static { System.out.println("Class loaded"); }
final Variables Creates constants that can’t be reassigned final int MAX_SIZE = 100;
final Methods Prevents method overriding in subclasses public final void display() { }
final Classes Prevents class inheritance public final class ImmutableString { }
final Method parameters Prevents parameter reassignment within method public void process(final int value) { }
static final Class constants Immutable class-level constants public static final String VERSION = "1.0";

Somethimes we use static and final together, an example demonstrating the use of final static variables in Java:

public class MathConstants {
    public static final double PI = 3.14159265359;
    public static final double E = 2.71828182846;
    public static final double GOLDEN_RATIO = 1.61803398875;

    public static void main(String[] args) {
        System.out.println("Value of PI: " + PI);
        System.out.println("Value of E: " + E);
        System.out.println("Value of Golden Ratio: " + GOLDEN_RATIO);

        // The following lines would cause compilation errors if uncommented:
        // PI = 3.14; // Error: cannot assign a value to final variable PI
        // E = 2.72; // Error: cannot assign a value to final variable E
    }
}

In this example:

  1. We declare three public static final variables: PI, E, and GOLDEN_RATIO. These are mathematical constants that should never change[2][4].

  2. The static keyword means these variables belong to the class itself, not to any specific instance of the class. They can be accessed directly through the class name, like MathConstants.PI[3].

  3. The final keyword ensures that these variables cannot be reassigned once they are initialized. This makes them true constants.

  4. We initialize these constants at the point of declaration. For final static variables, this is one of the valid ways to initialize them.

  5. In the main method, we print out the values of these constants.

  6. The commented-out lines demonstrate that attempting to reassign these constants would result in a compilation error.

Key points about final static variables:

  1. They must be initialized either at the point of declaration or in a static initializer block.
  2. They are often used for constants that are shared across all instances of a class.
  3. By convention, final static variables are usually named in ALL_CAPS with underscores separating words.
  4. They are evaluated at compile-time, which can lead to performance optimizations.

Using final static variables for constants provides several benefits: - It ensures the value cannot be changed accidentally. - It clearly communicates the intent that this value should not change. - It allows the compiler to perform optimizations, potentially improving performance.

Remember, while final prevents reassignment, if the constant is an object reference, the object’s internal state can still be modified unless the object itself is immutable.

6 final and immutable

The key differences between final and immutable in Java are:

6.1 Final

  1. Applies to variables, methods, and classes.
  2. For variables, prevents reassignment of the reference, but not modification of the object’s state.
  3. Ensures the variable will always point to the same object reference.
final List<String> list = new ArrayList<>();
list.add("Item"); // Valid: Modifying object state
// list = new ArrayList<>(); // Invalid: Reassignment not allowed

6.2 Immutable

  1. Applies to objects, not variables.
  2. Prevents any changes to the object’s state after creation.
  3. The object’s internal values cannot be modified once initialized.
String str = "Hello";
// str.toLowerCase(); // Returns a new String, doesn't modify original
// String is immutable, so its state can't be changed

6.3 Key Distinctions

  1. Scope: final is about reference constancy, while immutability is about object state constancy.

  2. Mutability: A final variable can still refer to a mutable object, whereas an immutable object’s state cannot be changed at all.

  3. Implementation: final is a keyword in Java, while immutability is a design principle implemented by the programmer.

  4. Flexibility: You can have a non-final reference to an immutable object, allowing the reference to be reassigned while the object remains unchangeable.

  5. Combination: An object can be both final and immutable, like the String class in Java.

Back to top