Faster, better AI-powered code reviews. Start your free trial!  
Faster, better AI-powered code reviews.
Start your free trial!

Get high quality AI code reviews

Java Inner Class Tutorial: Java Explained

Table of Contents

Inner classes play an integral role in the Java programming language. In this tutorial, we’re breaking down the basics so you can get up and running with inner classes. We’ll discuss what an inner class is, their benefits, how to create one, and the different types of inner classes available. Let’s get started!

What is an Inner Class in Java?

An inner class in Java is a class declared within another class. This class has access to the members of its containing class, including private fields and methods. Inner classes can also be declared as public, protected, and package-private, but not private. This means that an inner class has access to both the public and private members of its outer class.

Inner classes are often known as nested classes. These classes are nested within one another, making it possible for the inner class to access all the members of the outer class. This gives the inner class the ability to modify or hide the elements of the outer class.

What Are the Benefits of Using Inner Classes?

The major advantage of using inner classes is that they can provide a very modular way to incorporate functionality into your code. Inner classes can help you create robust code that is easy to maintain, test, and debug. Using inner classes can also encourage code reuse, which helps to save you time and effort.

Using inner classes also makes your code easier to read. Instead of dealing with unrelated classes that are unrelated to one another, they are contained in one smaller section of your code. This makes your code less cluttered, which helps make it easier to understand.

How to Create an Inner Class in Java

Creating an inner class in Java is straightforward and easy to do. All you need to do is declare a new class inside another class. The inner class will then have access to the outer class’s fields and methods. Here’s an example of how to create an inner class:

public class OuterClass {   ...  public class InnerClass {    ...   }   ... }

In this example, the InnerClass is the inner class. This class has access to the fields and methods of the outer class. It can then implement it’s functionality and use the outer class’s elements when needed.

Accessing Variables Inside an Inner Class

In order for an inner class to access variables from its containing class, those variables must be marked as ‘final’ or ‘effectively final’. Variables that are marked as ‘final’ cannot be changed once they are created; they will have the same value for the lifetime of the containing class. The same applies to variables that are marked as ‘effectively final’; these variables can be changed, but not after they have been referenced by the containing class.

For example:

public class OuterClass {   private final int x = 10;  public void printX() {    System.out.println(x);  }  public class InnerClass {     public void printXFromInner() {       System.out.println(x);    }   } }

In this example, the printXFromInner() method in the inner class can access the x variable from its containing class since it is marked as ‘final’. If the variable was not ‘final’, it would still be accessible from the inner class, but it would have to be marked as ‘effectively final’. This means that it cannot be changed after it is referenced by any code in the containing class.

Different Types of Inner Classes

There are several different types of inner classes available which all have their own unique characteristics. These include nested inner classes, static nested classes, anonymous inner classes, local classes, and lambda expressions.

Nested Inner Classes

Nested inner classes are classes that are defined inside another class. They have access to all elements of the outer class, and can even access private fields and methods.

public class OuterClass {   public int x;  public class NestedInnerClass {     public void showX() {       System.out.println(x);     }   } }

In this example, the NestedInnerClass has access to the x variable in its containing class, even though it is marked as public. It does not require any special accessor methods or constructors; it simply has access to all elements in its containing class.

Static Nested Classes

Static nested classes are similar to nested inner classes; however, their behavior is slightly different. In a static nested class, each instance of the outer class must create an instance of the inner class, even if it does not make use of it. Furthermore, static nested classes cannot directly access non-static members of its containing outer class.

public class OuterClass {   private int x;  public static class StaticNestedClass {     public void showX() {       System.out.println(x); // Not possible since x is not static     }   } }

In this example, the StaticNestedClass cannot directly access the x variable since it is marked as private. To gain access to this variable, a special accessor method would need to be created in the outer class that returns the value of x. This method can then be called from within the static nested class.

Anonymous Inner Classes

Anonymous inner classes are similar to regular inner classes; however, they do not have a name. They must be declared and instantiated at the same time and can only access local variables if those variables are marked as final. They are commonly used as anonymous callbacks or listeners.

public void doSomething() {   final int x = 10;   Runnable runnable = new Runnable() {     public void run() {       System.out.println(x); // Able to access x since it is marked as final     }   };  new Thread(runnable).run();  }

In this example, an anonymous inner class has been used to create a Runnable that can be passed into a new thread. Since the variable x is marked as final, it can be accessed from within the anonymous inner class.

Local Classes

Local classes are similar to anonymous inner classes; however, they must be defined within a block of code (e.g. within a method). Like anonymous inner classes, they can only access local variables if those variables are marked as final.

.

public void doSomething() {   final int x = 10;       // Declare a local class inside a block of code    class LocalClass {      public void showX() {        System.out.println(x); // Able to access x since it is marked as final       }     }     // Create an instance of local class     LocalClass localClass = new LocalClass();     localClass.showX();  }

In this example, a local class has been declared within a block of code and instantiated with an instance of itself. Since the x variable is marked as final, it can be accessed from within the local class.

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                                                                                                                                                                                                                                                                                                                                               anoogaTorgLsjtnadovtifmorfytrioaxosaonteyfodirmtaoretrocbopnotliatssiasmocficsrueoeademitmedasrksont.

Nisha Kumari

Nisha Kumari

Nisha Kumari, a Founding Engineer at Bito, brings a comprehensive background in software engineering, specializing in Java/J2EE, PHP, HTML, CSS, JavaScript, and web development. Her career highlights include significant roles at Accenture, where she led end-to-end project deliveries and application maintenance, and at PubMatic, where she honed her skills in online advertising and optimization. Nisha's expertise spans across SAP HANA development, project management, and technical specification, making her a versatile and skilled contributor to the tech industry.

Written by developers for developers

This article was handcrafted with by the Bito team.

Latest posts

Mastering Python’s writelines() Function for Efficient File Writing | A Comprehensive Guide

Understanding the Difference Between == and === in JavaScript – A Comprehensive Guide

Compare Two Strings in JavaScript: A Detailed Guide for Efficient String Comparison

Exploring the Distinctions: == vs equals() in Java Programming

Understanding Matplotlib Inline in Python: A Comprehensive Guide for Visualizations

Top posts

Mastering Python’s writelines() Function for Efficient File Writing | A Comprehensive Guide

Understanding the Difference Between == and === in JavaScript – A Comprehensive Guide

Compare Two Strings in JavaScript: A Detailed Guide for Efficient String Comparison

Exploring the Distinctions: == vs equals() in Java Programming

Understanding Matplotlib Inline in Python: A Comprehensive Guide for Visualizations

Related Articles

Get Bito for IDE of your choice