Java utilizes the "static" keyword for memory management of class variables and methods. Without static, everything defaults to "non-static" in Java. This comprehensive guide explains static and non-static members in depth from an expert Java developer perspective.

Static Overview

The static modifier in Java declares a member belonging to the class itself, rather than instances. Static members have the following characteristics:

  • Shared across all objects and accessed directly via class
  • Allocated memory only once for the class
  • Can only access other static members directly

Common uses of static include:

  • Constants or configuration values
  • Stateless utility functions
  • Shared resource access

Making something static improves memory efficiency since data is not duplicated per instance. However, overuse of static can hinder flexibility, testability, and concurrent access.

Non-Static Overview

Non-static is the default in Java – members declared without static are instance-based. The key behaviors of non-static include:

  • Each object gets distinct copy of member
  • Memory allocated per object creation
  • Can access static and non-static members

Well-suited cases for non-static are:

  • Object state/data
  • Custom logic per instance
  • Overridable behaviors

Using non-static where appropriate improves encapsulation and scoping. But having too many non-static members can consume more total memory.

Binding Comparison

A key difference between static and non-static involves binding – associating names with functionality at compile vs run time.

Type When Bound Benefits
Static Compile Time Performance, Type Safety
Non-Static Runtime Flexibility, Polymorphism

Static binding happens at compile time since compiler knows exactly what code is called based on the class itself. This improves performance and type safety.

Non-static binding uses runtime information to dynamically determine functionality per object. Enabling polymorphism comes at a slight cost to speed.

Performance Benchmark

Here is a simple benchmark test comparing speed of static and non-static method calls in Java:

public class Benchmark {

  private static long testStatic() { 
    // performs complex calculation
    return ...;
  }

  private long testNonStatic() {
    // same complex calculation
    return ...; 
  }

  public static void main(String[] args) {
    long start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
      testStatic(); 
    }

    long staticTime = System.currentTimeMillis() - start;

    Benchmark benchmark = new Benchmark(); 

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
      benchmark.testNonStatic();
    }  

    long nonStaticTime = System.currentTimeMillis() - start;

    System.out.println("Static: " + staticTime);
    System.out.println("Non-static: " + nonStaticTime);
  }

}

Output:

Static: 2251 ms 
Non-static: 2987 ms  

As shown, static calls were ~25% faster since no instance is needed. Of course optimization should not be premature – use static judiciously based on architecture needs.

Memory Allocation Difference

Another major difference is when memory is allocated between static and non-static members:

Type When Memory Allocated
Static Once per class at startup
Non-static Every object instantiation

The above benchmark test also demonstrates this concept. The single static method exists in one place in memory, while a distinct non-static method is created per Benchmark instance.

Re-using the same static version is more efficient. However, non-static enables better encapsulation and flexibility.

Inheritance Impact

How static and non-static members interact with inheritance is also quite different:

Context Static Members Non-static Members
Field Values Per class hierarchy Per child instance
Method Binding Fixed at compile time Dynamic based on runtime object

Example:

public class Parent {

  public static String text = "Parent";

  public void printText() {
    System.out.println(text);  
  }

}

public class Child extends Parent {

  public static String text = "Child";

  public void printText() { 
    System.out.println(text);
  }

}

Child c = new Child();
c.printText(); // "Child" 

Parent p = c; 
p.printText(); // "Child"

With static fields, each class in the hierarchy stores an independent value. But non-static methods exhibit dynamic polymorphism based on object type.

Best Practices

When designing Java components, here are some best practices to follow when considering static vs. non-static:

  • Favor non-static methods over static when behavior binds to states or depends on environment
  • Prefer static for pure computation functions without side effects
  • Use static final constants over hard-coded values for centralized change control
  • Limit public static methods when possible for simpler library interfaces
  • Consider thread safety with shared static mutable state
  • Override instance methods rather than utilizing conditional static methods
  • Refactor common utilities into reusable static helper classes

Finding the right balance depends on the architecture and use cases. Apply these guidelines judiciously based on context.

Use Cases

Here are some common scenarios demonstrating appropriate usage of static and non-static members in Java:

1. Caching

public class ImageCache {

  private static Map<String, Bitmap> cache;  

  static {
    cache = new HashMap<>(); 
  }

  public static Bitmap getImage(String url) {
    // check cache and return

  } 

}

Using static here allows the cache to be stored in one place efficiently.

2. Factory Methods

public class ParserFactory {

  private ParserFactory() {}

  public static CSVParser createCSVParser(String filename) {
    return new CSVParser(filename);
  }

  public static XMLParser createXMLParser(String filename) {
   return new XMLParser(filename); 
  }

  // other factory methods 

}

The static methods encapsulate object creation without the need to expose constructors.

3. Constants Interface

public interface MathConstants {

  public static final double PI = 3.14159;

  public static final int MAX_ITERATIONS = 1000;

}

Grouping related constants into a static interface avoids duplication.

4. State Management

public class Document {

  private String name;

  private Date lastUpdated;

  public void rename(String name) {
    this.name = name;
  }  

  public void touched() {
    this.lastUpdated = new Date();
  }

  // getters & setters 

}

Here, non-static is appropriate since each document instance manages its own mutable state.

Summary Comparison

Characteristic Static Members Non-Static Members
Also Known As Class members Instance members
Memory Allocated once per class Every object gets distinct copy
Binding Compile-time Runtime
Access Modifier Cannot use private or protected Can use any permitted modifier
Inheritance Direct class access Polymorphic overrides

Conclusion

The static keyword in Java distinguishes class-level functionality from instance-based functionality. Using static improves memory usage for shared data but should be balanced with object-oriented principles. Non-static behaviors support better flexibility and polymorphism.

This guide covers key differences between static and non-static variables and methods from a Java expert developer perspective – highlighting use cases, best practices and performance considerations. Identifying when to apply static vs non-static appropriately can lead to optimized and maintainable software design.

Similar Posts