×

Search anything:

Java Local Inner Classes

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article at OpenGenus, we will discuss what local inner classes are in Java, some properties of local inner classes in relation to standard inner classes/Java classes declared in a standalone files, and some use cases for local inner classes.

What are Local Inner Classes?

Syntactically, local inner classes, in Java are simply classes declared within the body of any code block, such as within a method body or within a loop. Furthermore, they are declared in the same way that you would declare a normal Java class, and can have fields and methods. It should be important to note that a local inner class is not an inner class, which is a class declared in the body of another class. The following sample declaration serves to illustrate how a local inner class may look like.

Sample Declaration:

public class Example {
    
    public void method() {
       
        // The local inner class. Notice how it is declared in the
        // body of method(). 
        
        class LocalInnerClass {
        
            int data; //Field
            
            public LocalInnerClass(int num) {
                data = num;
            }

            // Methods.
            public void doNothing() {
            }
            
            public void doSomething() {
                data = 3;
            }
        }
    }
}

Properties of Local Inner Classes

Now that you know the relevant syntax on how to declare a local inner class, we will now go over what makes local inner classes distinct from standalone Java classes and even standard inner classes.

One important difference that you might be able to intuit from the way it is declared is that local inner classes have block scope in the block in which it was declared. What this means is that the local inner class is not visible outside whatever method, if statement, or other such block construct in which it resides in. Also, since they are local, like local variables, local inner classes cannot have keywords like "private", "public", or "static". As an aside, because interfaces are implicitly static, you cannot have a local interface.

It should be noted that regardless of where a local inner class is declared, it follows that the code block the local class resides in must itself reside in the body of a class. And like normal inner classes, local inner classes have access to the data (fields and methods) of its enclosing class, even if they are declared private. Like non-static inner classes, they also cannot declare static members due to their association with an instance of the enclosing class. The exception is for constants that are declared both static and final.

However, since the class is local, it can also access the local variables/parameters that are in scope, provided that they are declared final or effectively final (their value does not change after being initialized). Note that accessing effectively final variables is only a feature from Java SE 8 and onwards.

Example:

public class Example {
    private int field = 2;
    
    public void method() {
        final int number = 1;
        int notfinal = 0;
        
        class LocalInnerClass {

            public void printField() {
                // Can access enclosing class's private fields/methods.
            
                System.out.println(field);
                method2();
            }
            
            public void printFinal() {
                // Can access number because number is declared final.
                
                System.out.println(number);
            }
            
            public void printNotFinal() {
                // Allowed because notfinal doesn't change.
                
                System.out.println(notfinal);
            }
        }
    }
    
    private void method2() {
        System.out.println("a method");
    }
}

Normally, local variables go out of existence as soon as they leave scope, but instances of local classes can persist beyond the scope in which they were instantiated. Because of this discrepancy between local variables and local classes, if an instance of the local class accesses a local variable, it can create an interesting situation where the life of a local variable is seemingly "prolonged". The following example serves to illustrate this concept.

Example:

public class Example {
    
    // Nested interface
    interface Item {
        public int returnValue();
    }
    
    public static void main(String args[]) {
        Item items = new Item[5];
        
        for (int i = 0; i < 5; i++) {
            final int num = i;
            
            // Local inner class implements Item so we can store them outside
            // for loop in items array.
            
            class LocalItem implements Item {
            
                // Method returns the final local variable num, which stores the
                // current index of the LocalItem.
                
                public int returnValue() {
                    return num;
                }
            }
            
            items[i] = new LocalItem();
        }
    }
    
    // LocalItem has gone out of scope, so the final local variable "num" has also
    // gone out of scope. However, when we call returnValue() on each of the
    // LocalItem objects in the array, it still prints "0 1 2 3 4" as if each 
    // individual local num still exists. This is because Java is lexically scoped, 
    // which you can read more about elsewhere if you're curious.
    
    for (int i = 0; i < 5; i++)
        System.out.println(items[i].returnValue());

}

Example Usages of Local Inner Classes

After gaining some understanding of what local inner classes are and how they work, it's time to see some use cases for local inner classes.

Like with standard inner classes, local inner classes represent a great way to logically group data/functionality, and like with inner classes, they are usually best used in situations where the class is intimately related to the processes of the enclosing class/block (E.g. some private helper or component class). However, because a local inner class exists within a smaller block of code, it should be used for situations where the class is only needed within that specific area of code.

A great example of that would be in a class that implements the Iterable interface. Since only the iterator() method really needs to know about the Iterator, it can declare the Iterator class definition within its own body, and it makes it clear to any external reader that these two definitions are tightly coupled. Furthermore, the Iterator local inner class would be able to access the private data of the enclosing class that it needs for its operations, which if you recall was one of the features we mentioned earlier.

Example:

public class MyList implements Iterable<Integer> {
    private int[] elts;
    
    public MyList(int size) {
        elts = new int[size];
    }
    
    // Methods of the MyList class
    ...
    
    // Returns an instance of the local inner class, which is
    // the Iterator. Although the class goes out of scope once
    // the method call is over, you can still refer to the returned
    // instance if you store it with an interface reference and call the 
    // relevant public methods on it such as next(), hasNext(), and so on.
    
    public Iterator<Integer> iterator() {
        class MyListIterator implements Iterator<Integer> {
            ...
        }
        return new MyListIterator();
    }

}

Summary

To recap, today you have learned that:

  • Local inner classes are classes declared in a block like local variables
  • Local inner classes can access private fields/methods of its enclosing class (like inner classes)
  • Local inner classes can only access final or effectively final local variables
  • Local inner classes can "prolong" the life of local variables
  • Local inner classes are good as helper/component classes for individual methods
Java Local Inner Classes
Share this