Static vs Non-Static (Java)

General Definition

In general, something defined as static just means that a class instance (object) is not required to access it. Since it is "static", it only exists in one form, as opposed to being "dynamic", where it may be different depending on the instance.

Variable Level (Fields/Class Variables vs. Instance Variables)

Static

A static variable is defined at the class level (outside of any methods) and can be accessed by other classes without instantiating the class.

E.g. x = ClassName.staticVariableName; (assuming that the variable is not private).
But remember, a static variable can be accessed from an instance; it is just unneccesary.
E.g. x = ClassInstance.staticVariableName;
or x = new ClassName(args).staticVariableName;.

It may be called a class variable or a field. It is called a class variable because the variable belongs to the class as a whole, not any specific instance of the class. All instances have this variable in common, and so this variable may be referenced from the class without an instance of it (object).

For example, you may want to keep track of the number of instances created. So if you had the class Student, you can have a class variable called numberOfStudents.

Non-static

An non-static variable is defined at the class level (outside of any methods), but requires a class instance to be accessed.

E.g. x = ClassInstance.instanceVariableName;
or x = new ClassName(args).instanceVariableName; (assuming that the variable is not private). It is called an instance variable because it is specific to the instance created.

For example, let's say you had a class called Student and so every class instance (object) was a new student. The name of each student would be stored as an instance variable, since the name is specific to every instance (every student).

Look at an example of the complete picture:

public class Student {

    public String name = ""; // instance variable
    public static int numberOfStudents = 0; // class variable or field
    
    // constructor method
    public Student (String name) {
        this.name = name;
        this.numberOfStudents++;
    }
}

public class TestClass {
    public void testMethod() {
    
        Student student1 = new Student("Foo");
        
        // accessing static variable
        System.out.println(Student.numberOfStudents); // prints "1"
        System.out.println(student1.numberOfStudents); // prints "1"
        
        Student student2 = new Student("Bar");
        
        // accessing static variable
        System.out.println(Student.numberOfStudents); // prints "2"
        System.out.println(student2.numberOfStudents); // prints "2"
        
        // accessing instance variable
        System.out.println(Student.name); // doesn't work - what would the value be?!
        System.out.println(student1.name); // prints "Foo"
        System.out.println(student2.name); // prints "Bar"
    }
}

Constants (declared as final), such as public static final TAX_RATE = 0.13;, are often static because they may be constant, relative of context. In the TAX_RATE example, the tax rate may be the same regardless of the instance created. For example, if the objects were items, the tax could be the same for all items. However, if the objects were countries, the tax rate may vary. Therefore, the TAX_RATE variable should not be declared static in that case.

Method Level (Class Methods vs Instance Methods)

Static

A static method is a method that can be accessed from any class without a class instance. However, it can be accessed from an instance, but is not necessary.

E.g. ClassName.staticMethod(); // correct approach
or ClassInstance.staticMethod(); // calling from instance
or new ClassName.staticMethod(); // calling from instance

This type of method is called a class method since it is a member of the class as a whole, not any specific instance of it. The method does not perform a task related to any specific instance. The method is called from the general class.

For example, let's say we have the class Height. And let's say we have a method that converts inches into centimeters (heights for different number systems) called convertInToCm(double). Is that method related to any specific Height object? Or is it only relative to the class in general? The answer is the latter, so the method can be defined as a class method (static).

Non-static

A non-static method is a method that requires a class instance to be accessed.

E.g. ClassInstance.instanceMethod();
or new ClassName.instanceMethod();

This type of method is called an instance method since the method is specific to the instance created.

For example, if a Height object was created and we wanted to call a method that returns the height of that object, is the method a class or instance method? It's an instance method, since the height is specific to that instance. Getter and setter methods are typically instance methods, since they typically return a value related to that specific object created.

Look at an example of the complete picture:

public class Height {
    
    private double height = 0.0; // instance variable: height of object in centimeters
    private static final double INCH_TO_CM_RATIO = 2.54; // class constant variable that represents the ratio of 1 inch to 1 centimeter

    // constructor method
    public Height(double height) {
        this.height = height;
    }
    
    // getter method
    public double getHeight() {
        return this.height;
    }
    
    // class method for height conversion
    public static double convertInToCm(double inches) {
        return inches * INCH_TO_CM_RATIO;
    }
}

public class TestClass {
    public void testMethod() {
        
        Height height1 = new Height(185.42); // creates Height object of 185.42 cm
        
        double heightInInches = 73; // 73 inches
        double heightInCm = Height.convertInToCm(heightInInches); // returns 73 inches to the cm equivalent (185.42 cm)
        
        Height height2 = new Height(heightInCm); // creates Height object of 73 inches or 185.42 cm
        Height height3 = new Height(Height.convertInToCm(73)); // the same as height2
        
    }
}

Keep in mind that non-static references (instance variables, instance methods and class instances) cannot be made from a static method. This is because a static method can be accessed WITHOUT any instance created. So if you reference methods or variables that require an instance, what would happen?

Look at the following example of how that could go wrong:

public class MyClass {

    private String name = ""; // instance variable
    
    // constructor method
    public MyClass (String name) {
        this.name = name;
    }
    
    // getter method for name (instance method)
    public String getName() {
        return this.name;
    }
    
    public static void staticMethod() {
        System.out.println(getName()); // ERROR. Can't call instance method from class method.
    }
}

public class TestClass {
    public void testMethod() {
        MyClass.staticMethod(); // What would be printed? By default, the name is "".
                                // No name is set until an instance is created (constructor method)!
    }
}

Class Level

You can only declare a nested class as static, since declaring an entire class as static would be useless. An inner class is a non-static nested class (as opposed to a static nested class).

The difference between an inner class and a static nested class is that a static nested class can have its methods accessed without instantiating the static nested class. An inner class must be instantiated to access its methods, and therefore the outer class must be instantiated as well.

Look at the following example for use of static vs non-static nested classes:

public class OuterClass {
	
    public OuterClass(int i) { }
	
    public static class StaticNestedClass {
    	public void instanceMethod() { }
    	public static void staticMethod() { }
    }

    public class InnerClass { }
}

public class TestClass {
    public void testMethod() {
        // Use of a static nested class:
        
        // Instantiate the static nested class:
        
        // access the static nested class WITHOUT instantiating the static nested class
        OuterClass.StaticNestedClass staticNestedClass = new OuterClass.StaticNestedClass(); // works
        
        // Use the methods inside the static nested class:
        
        staticNestedClass.staticMethod(); // works
        staticNestedClass.instanceMethod(); // works

        // (instantiate the outer class to have access to the instance method inside the static nested class)
        new OuterClass.StaticNestedClass().instanceMethod(); // works
        
        // access the STATIC method inside the static nested class WITHOUT any instantiating
        OuterClass.StaticNestedClass.staticMethod(); // works
        
        // access the INSTANCE method inside the static nested class WITHOUT any instantiating
        //OuterClass.StaticNestedClass.instanceMethod(); // doesn't work
        
        // access the INSTANCE method inside the static nested class WITH instantiating the outer class
        new OuterClass.StaticNestedClass().instanceMethod(); // works

        
        // Use of an inner class:
        
        // Instantiate the inner class:
        
        // access the inner class WITHOUT instantiating the inner class
        OuterClass.InnerClass innerClass = new OuterClass.InnerClass(); // doesn't work
        // access the inner class WITH instantiating the inner class
        OuterClass.InnerClass innerClass2 = new OuterClass(5).new InnerClass(); // works
    }
}

          Created: June 1, 2015
Completed in full by: Michael Yaworski