Have you ever wonder why we have 4 kinds of different nested classes? What is the main difference between them? How we use it and where?
In this post, I will concentrate on the inner and inner static classes only. There are a couple of differences between them, but the main ones are the instantiation of classes and accessibility to enclosing(outer) instances.
Let’s look at below example of Inner class:
public class Outer { private String outerValue = "outer class value"; public String getOuterValue() { return outerValue; } public void setOuterValue(String outerValue) { this.outerValue = outerValue; } public class Inner { private String innerValue = "inner class value"; public String getInnerValue() { return innerValue; } public void setInnerValue(String innerValue) { this.innerValue = innerValue; } public void setParentValue(String newValue) { outerValue = newValue; } public String getParentValue() { return outerValue; } } }
public class TestMyClasses { public static void main(String[] args) { //inner class, have access to outer class instance/variables Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); inner.getParentValue(); } }
From the above example, you can see that inner class have access to enclosing instance. This behaviour has a hidden extraneous reference to it’s enclosing instance. It’s bad because this reference takes time, space and also could cause a memory leak. What is it good for? One common use of a nonstatic member class is to define an Adapter.
// Typical use of a nonstatic member class public class MySet<E> extends AbstractSet<E> { ... // Bulk of the class omitted public Iterator<E> iterator() { return new MyIterator(); } private class MyIterator implements Iterator<E> { ... } }
Let’s look at below example of Inner static class:
public class Outer { private String value = "outer class value"; public String getValue() { return value; } public void setValue(String value) { this.value = value; } public static class InnerStatic { private String innerValue = "inner static class value"; public String getInnerValue() { return innerValue; } public void setInnerValue(String innerValue) { this.innerValue = innerValue; } } }
public class TestMyClasses { public static void main(String[] args) { //inner static class, don't have access to outer class instance/variables Outer.InnerStatic innerStatic = new Outer.InnerStatic(); } }
Inner static class doesn’t have access to it’s enclosing instance and also instantiation is different. Where we use it? One of my favourite examples is the Builder pattern.
public class BankAccount { //Fields omitted for brevity. private BankAccount() { } //Getters and setters omitted for brevity. public static class Builder { private long accountNumber; private String owner; private String branch; private double balance; private double interestRate; public Builder(long accountNumber) { this.accountNumber = accountNumber; } public Builder withOwner(String owner){ this.owner = owner; return this; } public Builder atBranch(String branch){ this.branch = branch; return this; } public Builder openingBalance(double balance){ this.balance = balance; return this; } public Builder atRate(double interestRate){ this.interestRate = interestRate; return this; } public BankAccount build(){ BankAccount account = new BankAccount(); account.accountNumber = this.accountNumber; account.owner = this.owner; account.branch = this.branch; account.balance = this.balance; account.interestRate = this.interestRate; return account; } } }
BankAccount account = new BankAccount.Builder(12345L) .withOwner("Karen") .atBranch("Grygoryan") .openingBalance(1_000_000_000)// At least I can dream! .atRate(2.5) .build();
As we seen from several examples in this post, each nested class has it’s place. If nested class needs access to enclosing class make it non-static and use with caution, otherwise make it static. Hope you liked this post, will be glad to hear your feedback.