Static vs Non Static Nested Classes


Nested and Inner Classes

Using Java, developers have the ability to define a class within another class. Such a class is called a Nested Class. Nested Classes are called Inner Classes if they were declared as non-static, if not, they are simply called Static Nested Classes. This page is to document and provide details with examples on how to use Java Nested and Inner Classes.


A Simple Stack Using a Nested Class

public class CustomStack {
    private CustomStackNode top;
 
    private static class CustomStackNode {
        private int value;
        private CustomStackNode next;
 
        private CustomStackNode(int val, CustomStackNode next) {
            value = val;
            this.next = next;
        }
    }
 
    public CustomStack push(int val) {
        top = new CustomStackNode(val, top);
        return this;
    }
 
    public int pop() {
        int x = top.value;
        top = top.next;
        return x;
    }
 
    public static void main(String[] args) {
        CustomStack customStack = new CustomStack();
        customStack.push(9).push(8).push(7).push(6).push(5);
 
        // Prints: 5, 6, 7, 8, 9,
        for (int i = 0; i < 5; i++) {
            System.out.print(customStack.pop() + ", ");
        }
    }
}

Static vs Non Static Nested Classes

When creating a nested class, you face a choice of having that nested class static:

public class OuterClass1 {
	private static class StaticNestedClass {
 
	}
}

Or non-static:

public class OuterClass2 {
	private class NestedClass {
 
	}
}

At its core, static nested classes do not have a surrounding instance of the outer class, whereas non-static nested classes do. This affects both where/when one is allowed to instantiate a nested class, and what instances of those nested classes are allowed to access. Adding to the above example:

public class OuterClass1 {
 
	private int aField;
	public void aMethod(){}
 
	private static class StaticNestedClass {
		private int innerField;
		private StaticNestedClass() {
			innerField = aField; //Illegal, can't access aField from static context
			aMethod(); //Illegal, can't call aMethod from static context
		}
		private StaticNestedClass(OuterClass1 instance) {
			innerField = instance.aField; //Legal
		}
	}
 
	public static void aStaticMethod() {
		StaticNestedClass s = new StaticNestedClass(); //Legal, able to construct in static context
		//Do stuff involving s...
	}
}
 
public class OuterClass2 {
 
	private int aField;
 
	public void aMethod() {}
 
	private class NestedClass {
 
		private int innerField;
 
		private NestedClass() {
			innerField = aField; //Legal 
			aMethod(); //Legal
		}
	}
 
	public void aNonStaticMethod() {
		NestedClass s = new NestedClass(); //Legal
	}
 
	public static void aStaticMethod() {
		NestedClass s = new NestedClass(); //Illegal. Can't construct without surrounding 	OuterClass2 instance.
	                                       //As this is a static context, there is no surrounding OuterClass2 instance
	}
}

Thus, your decision of static vs non-static mainly depends on whether or not you need to be able to directly access fields and methods of the outer class, though it also has consequences for when and where you can construct the nested class.

As a rule of thumb, make your nested classes static unless you need to access fields and methods of the outer class. Similar to making your fields private unless you need them public, this decreases the visibility available to the nested class (by not allowing access to an outer instance), reducing the likelihood of error.


Access Modifiers for Inner Classes

A full explanation of Access Modifiers in Java can be found here. But how do they interact with Inner classes?

public, as usual, gives unrestricted access to any scope able to access the type.

public class OuterClass {
 
	public class InnerClass {
		public int x = 5;
	}
 
	public InnerClass createInner() {
		return new InnerClass();
	}
}
 
public class SomeOtherClass {
 
	public static void main(String[] args) {
		int x = new OuterClass().createInner().x; //Direct field access is legal
	}
}

oth protected and the default modifier (of nothing) behave as expected as well, the same as they do for non-nested classes.

private, interestingly enough, does not restrict to the class it belongs to. Rather, it restricts to the compilation unit - the .java file. This means that Outer classes have full access to Inner class fields and methods, even if they are marked private.

public class OuterClass {
 
	public class InnerClass {
		private int x;
		private void anInnerMethod() {}
	}
 
	public InnerClass aMethod() {
		InnerClass a = new InnerClass();
		a.x = 5; //Legal
		a.anInnerMethod(); //Legal
		return a;
	}
}

The Inner Class itself can have a visibility other than public. By marking it private or another restricted access modifier, other (external) classes will not be allowed to import and assign the type. They can still get references to objects of that type, however.

public class OuterClass {
 
	private class InnerClass{}
 
	public InnerClass makeInnerClass() {
		return new InnerClass();
	}
}
 
public class AnotherClass {
	public static void main(String[] args) {
		OuterClass o = new OuterClass();
 
		InnerClass x = o.makeInnerClass(); //Illegal, can't find type
		OuterClass.InnerClass x = o.makeInnerClass(); //Illegal, InnerClass has visibility private
		Object x = o.makeInnerClass(); //Legal
	}
}

Basic Programs