Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Static vs Instance Members and Proper equals/hashCode Implementation

Tech May 8 3

Static vs Instance Variables and Methods

In object-oriented languages like Java, static members belong to the class itself rather than any specific instance. A static variable is initialized when the class is loaded and shared across all instances. In cotnrast, instance (non-static) variables are created separate for each object upon instantiation.

Consider this example:

public class Example {
    private static String classField = "Shared";
    private String instanceField;

    public Example(String value) {
        this.instanceField = value;
    }

    public static void main(String[] args) {
        Example obj = new Example("Unique");
        System.out.println(obj.classField);      // Warning: accessing static via instance
        // System.out.println(Example.instanceField); // Compile error: non-static field
    }
}

Accessing a static field through an instance reference is discouraged and generates a warning. Conversely, referencing a non-static field from a static context (like main) results in a compilation error.

A common mistake is declaring collection fields as static when they should be per-instance. For example, in a graph class meant to represent individual friendship networks, using a static Set<String> to store nodes causes all instances to share the same set—leading to test contamination or incorrect behavior when multiple graphs exist concurrently. The fix is to remove static, ensuring each graph maintains its own node set.

Regarding methods:

  • static methods can only directly access other static members and cannot use this or super.
  • Instance methods can access both static and non-static members.
  • The main method must be static so the JVM can invoke it without creating an instance.

Implementing equals and hashCode

The default Object.equals() uses reference equality (==). To enable logical equality based on content, override equals. However, if two objects are equal according to equals, they must return the same hashCode. Violating this breaks hash-based collections like HashMap or HashSet.

Only overriding equals works functionally but harms performence in large collections, as hash codes enable fast bucket lookups before invoking equals. Only overriding hashCode is invalid—it violates the contract that equal objects must have equal hash codes.

A standard approach for hashCode uses prime multiplication (commonly 31):

@Override
public int hashCode() {
    final int prime = 31;
    int hash = 1;
    hash = prime * hash + (field1 == null ? 0 : field1.hashCode());
    hash = prime * hash + (field2 == null ? 0 : field2.hashCode());
    return hash;
}

This leverages the fact that 31 allows efficient computation via bit shifts (31 * n == (n << 5) - n) and reduces collision likelihood due to its primality.

Override both methods only when object equality matters—e.g., for Person objects used as map keys—but skip them for classes like FriendshipGraph if graph comparison isn’t required.

Tags: Java

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.