Java Nested Class Basics Explained

Java Nested Class Basics Explained

 

content

content

Java Nested Class Basics Explained

1. What is a nested class?

2. Why use nested classes?

3. Types of Nested Classes

4. Static Nested Classes

5. Non-static nested classes

5.1 Member inner class

5.2 Local inner classes

5.3 Anonymous inner classes

6. Nested Interfaces

 

 

1. What is a nested class?

In the Java language, it is allowed to define a class within another class, such a class is called a nested class. A class containing a nested class is called an outer class, and it can also be called an enclosing class, which is collectively called an outer class in this article.

Syntax of inner class:

class OuterClass {
    // code
    class NestedClass {
      // code
    }
}

Nested classes fall into two categories:

  • Static nested classes (Static nested classes): Use static declarations, generally called nested classes (Nested Classes).
  • Non-static Nested Classes (Non-static Nested Classes): Non-static declarations, generally called inner classes (Inner Classes).
class OuterClass {
  ...
  static class StaticNestedClass {
    ...
  }
  class InnerClass {
    ...
  }
}

A nested class is a member of its outer class, a non-static nested class (inner class) can access other members of the outer class even if the member is private. A static nested class can only access static members of the outer class.

A nested class, as a member of an outer class, can be declared as: private,public,protected or package scope (note: outer classes can only be declared public or package scope).

 

2. Why use nested classes?

The main advantages of using nested classes are as follows:

  • A nested class can access all data members and methods of the outer class, even if it is private.
  • Improve readability and maintainability: Because if a class is only available to another class, it is easier to understand and maintain by keeping them together.
  • Improve encapsulation: Given two classes A and B, if you need to access private members in class A, you can encapsulate class B in class A, which not only allows class B to access private members in class A, and Class B itself can be hidden from the outside.
  • Reduce the amount of code to write.

 

3. Types of Nested Classes

As mentioned above, nested classes are divided into static nested classes and non-static nested classes. Non-static nested classes are also called inner classes (inner classes are a subset of nested classes).

A static nested class can use the name of the outer class to access it. E.g:

OuterClass.StaticNestedClass

If you want to create objects for static nested classes, use the following syntax:

OuterClass.StaticNestedClass nestedObject =
        new OuterClass.StaticNestedClass();

Non-static nested classes (inner classes) can be divided into the following three types:

  • Member inner class
  • Anonymous inner class
  • Local inner class

type describe
member inner class Classes created within classes and outside of methods
anonymous inner class A class created to implement an interface or to extend a class, its name is determined by the compiler
local inner class class created inside method
static nested class static class created in class
nested interface An interface created in a class or in an interface

 

4. Static Nested Classes

A static nested class is actually a top-level class encapsulated in a top-level class. Its behavior is the same as that of a top-level class. It is encapsulated in a top-level class for the convenience of packaging.

  • A static nested class is a static member of the outer class, which can directly access itself using the outer class name.Static nested class name.
  • It can access static members and static private members of the outer class.
  • Like other classes, static nested classes cannot access non-static members.

The syntax of a static nested class is as follows:

class OuterClass{  
    // Static data members of outer classes
    static int data = 30;  
    // Static nested class in outer class
    static class StaticNestedClass {  
        // Instance methods in static nested classes
        void getData() {System.out.println("data is "+data);}  
    }

    public static void main(String args[]){  
        // Instantiate static nested classes (create objects)
        OuterClass.StaticNestedClass obj = new OuterClass.StaticNestedClass();  
        obj.getData();  
    }  
}  

Output result:

data is 30

In the above example, you need to create an instance of the static nested class first, because you need to access its instance method getData(). But you don't need to instantiate the outer class, because the static nested class is static relative to the outer class, you can directly use the outer class name.Static nested class name to access.

Static nested classes generated by the compiler:

import java.io.PrintStream;  
    static class OuterClass$Inner  
    {  
    OuterClass$StaticNestedClass(){}  
        void getData(){  
            System.out.println((new StringBuilder()).append("data is ")
            .append(OuterClass.data).toString());  
    }    
}  

As can be seen from the above code, the static nested class actually accesses the static members of the outer class directly through OuterClass.data.

Example of static method using static nested class:

If there are static members in a static nested class, they can be accessed directly without instantiating the static nested class.

class OuterClass2{  
    static int data = 10;  
    static class StaticNestedClass{  
        // Static method of static nested class
        static void getData() {System.out.println("data is "+data);}  
    }  

    public static void main(String args[]){  
        // No need to create an instance can be accessed directly
        OuterClass2.StaticNestedClass.getData();
    }  
}  

Output result:

data is 10

 

5. Non-static nested classes

A non-static nested class is also an inner class, which has the following characteristics:

  • To instantiate an inner class, you must first instantiate an outer class.
  • The inner class instance is associated with the outer class instance, so no static members can be defined in the inner class.
  • Inner classes are non-static.

See the detailed introduction below ↓

5.1 Member inner class

A non-static nested class that is created in an outer class and outside a method of the outer class is called a member inner class. To put it bluntly, the member inner class is just a non-static member of the outer class.

The syntax is as follows:

class OuterClass{  
    //code  
    class MemberInnerClass{  
        //code  
    }  
}  

Example of member inner class:

In the example below, we have created two instance methods getData() and getTest() in the member inner class and these two methods are accessing private data members and member methods in the outer class.

class OuterClass {  
    private int data = 30;  
    public void test() {System.out.println("i'm an outer class member method");}
    class MemberInnerClass {  
        // Access private data members of outer classes
        void getData() {System.out.println("data is "+data);}  
        // Access member methods of outer classes
        void getTest() {OuterClass.this.test();}
    }  

    public static void main(String args[]) {  
        // The outer class must be instantiated first
        OuterClass obj = new OuterClass();  
        // Then create the inner class object from the outer class object
        OuterClass.MemberInnerClass in = obj.new MemberInnerClass();  
        in.getData();
        in.getTest();  
    }  
}  

Output result:

data is 30
 i'm an outer class member method

When accessing a member method of an external class, you can call it directly through the external class name.this.External class member method(), or directly use the external class member method() to call.

How member inner classes work:

The Java compiler creates two .class files, one of which is the member inner class OuterClass$MemberInnerClass.class, and the member inner class file name format is outer class name $ member inner class name.

If you want to create an instance of a member inner class, you must first instantiate an outer class, and then create an instance of the member inner class from an instance of the outer class. Therefore an instance of the member inner class must exist within an instance of the outer class. Also, since an instance of the inner class is associated with an instance of the outer class, it cannot define any static members.

Member inner class code generated by the compiler:

In the example below, the compiler creates an inner class file named OuterClass$MemberInnerClass, the member inner class has a reference to the outer class, that's why it has access to all outer class members including private ones.

import java.io.PrintStream;  
    class OuterClass$MemberInnerClass {  
        final OuterClass this$0;  
        OuterClass$MemberInnerClass() {
            super();  
            this$0 = OuterClass.this;// external class is referenced
        }  
        void getData() {  
            System.out.println((new StringBuilder()).append("data is ")  
            .append(OuterClass.access$000(OuterClass.this)).toString());  
        }  
}  

5.2 Local inner classes

Local inner class es are usually defined in a block. So usually you'll find local inner classes inside a method block.

As with local variables, the scope of a local inner class is limited by the method. It can access all members of the outer class, and all local variables in the local method where it is located.

If you want to call a method in a local inner class, you must first instantiate the local inner class in the local method.

See the example below:

public class localInner {  
    private int data = 30;// instance variable

    // instance method
    void display() {  
        // local inner class
        class Local{  
            void msg() {System.out.println(data);}  
        }  
        // Access methods in local inner classes
        Local l = new Local();  
        l.msg();  
    }  

    public static void main(String args[]){  
        localInner obj = new localInner();  
        obj.display();  
    }  
}

output result

30

Local inner class code generated by the compiler:

At this point the compiler creates a class called localInner$Local which has a reference to the outer class

import java.io.PrintStream;  

class localInner$Local {  
    final localInner this$0;  // auto-generated local variables
    localInner$Local() {
        super();  
        this$0 = localInner.this;  
    }  

    void msg()  
    {  
        System.out.println(localInner.access$000(localInner.this));  
    }  
}  

Some rules for local inner classes:

  • Cannot call local inner class from outside method
  • Local inner classes cannot be declared as private, public, protected
  • Before JDK1.7, local inner classes cannot access non-final local variables, but in JDK1.8 and later, non-final local variables can be accessed.

Example of local inner classes and local variables:

class localInner2 {  

    private int data = 30;//instance variable

    void display() {  
        int value = 50;//Local variables must be declared 'final' before Jdk1.7

        class Local{  
            void msg() {System.out.println("value: "+value);}  
        }  

        Local l = new Local();  
        l.msg();  
    }  

    public static void main(String args[]){  
        localInner2 obj = new localInner2();  
        obj.display();  
    }  
}  

output result

value: 50

5.3 Anonymous inner classes

Inner classes that are not named in Java are called anonymous inner classes, which are used when we need to override methods in a class or interface. Anonymous inner classes are declared and instantiated at the same time when they are used.

Anonymous classes can be created in two ways:

  • Class (may be abstract class or other class)
  • interface

Use class to create anonymous inner class:

abstract class Person {  
	abstract void eat();  
}  

public class TestAnonymousInner {   
	public static void main(String[] args){
		// Instantiate abstract class Person with anonymous inner class
		Person p = new Person() {  
			void eat() {System.out.println("nice fruits");}  
		};

		p.eat();
	}  
}  

output result

nice fruits

There is the following paragraph in the above code:

Person p = new Person() {  
    void eat() {System.out.println("nice fruits");}  
};

It has two main functions:

  • Creates an anonymous inner class whose name is determined by the compiler and gives the implementation of the eat() method in the Person class.
  • An object of anonymous class is created and referenced using a reference variable p of type Person.

Anonymous inner class code generated by the compiler:

import java.io.PrintStream;  
static class TestAnonymousInner$1 extends Person  
{  
   TestAnonymousInner$1(){}  
   void eat() {  
        System.out.println("nice fruits");  
    }  
}  

From the above code, we can see that the compiler actually named the anonymous inner class TestAnonymousInner$1 and inherited the abstract class Person.

Create an anonymous inner class with an interface:

interface Eatable{  
    void eat();  
}  

class TestAnnonymousInner1{  
    public static void main(String args[]){  
        // Create anonymous inner class to implement interface Eatable
        Eatable e = new Eatable() {  
            public void eat(){System.out.println("nice fruits");}  
        };  

        e.eat();  
    }  
}  

output result

nice fruits

The above code has the following paragraph:

Eatable e = new Eatable() {  
    public void eat(){System.out.println("nice fruits");}  
};  

It has two main functions:

  • Creates an anonymous class whose name is determined by the compiler and gives the implementation of the eat() method.
  • An object of anonymous class is created and referenced using a reference variable p of type Person.

Anonymous inner class code generated by the compiler:

import java.io.PrintStream;  
static class TestAnonymousInner1$1 implements Eatable  
{  
    TestAnonymousInner1$1(){}  
        void eat(){System.out.println("nice fruits");}  
}  

From the above code we can see that the compiler actually creates a class named TestAnonymousInner1$1 and uses this class to implement the Eatable interface.

 

6. Nested Interfaces

The previous article mainly introduced the knowledge related to nested classes. Nested interfaces in Java are similar to nested classes. Let's take a look at the knowledge about nested interfaces.

Nested Interface refers to an interface created within a class or interface. Nested interfaces are used to group related interfaces for easier maintenance. Nested interface must be referenced by outer interface or outer class, it cannot be accessed directly.

Points to remember about nested interfaces:

Here are the main points Java programmers should remember about nested interfaces:

  • A nested interface declared in an interface has the default modifier public and must also be public, but a nested interface declared in a class can use any access modifier.
  • Nested interfaces are implicitly declared static.

Declare nested interfaces within interfaces:

interface interface_name{  
    ...  
    interface nested_interface_name{  
    ...  
    }  
}   

Declare nested interfaces in a class:

class class_name{  
    ...  
    interface nested_interface_name{  
    ...  
    }  
}   

Example of declaring a nested interface within an interface:

In the following example, we will learn how to declare a nested interface and how to use it.

interface Showable{  
	void show();  
	// declare nested interfaces
	interface Message{  
		void msg();  
	}  
}  

class TestNestedInterface1 implements Showable.Message{  
	// Implement the msg() method in the nested interface Message
	public void msg() {System.out.println("Hello nested interface");}  

	public static void main(String args[]){  
		// Instantiate the TestNestedInterface1 class and upcast it to the Showable.Message interface type
		Showable.Message message = new TestNestedInterface1();  
		message.msg();  
	}  
}  

Output result:

Hello nested interface

As seen in the above example, we cannot access the nested interface Message directly, but we can access it through the outer interface Showable.

It's like the wardrobe in the room, we can't get the clothes in the wardrobe directly, we have to enter the room first.

Code for the nested interface Message generated by the compiler:

public static interface Showable$Message  
{  
  public abstract void msg();  
}  

As you can see from the above code, the nested interface is actually declared as static.

Example of declaring nested interfaces in a class:

class A{  
	interface Message{  
		void msg();  
	}  
}  

class TestNestedInterface2 implements A.Message{  
	// Implement the msg() method in the Message interface
	public void msg() {System.out.println("Hello nested interface");}  

	public static void main(String args[]){  
		// Instantiate the TestNestedInterface2 class and upcast it to the A.Message type
		A.Message message = new TestNestedInterface2();
		message.msg();  
	}  
}  

Output result:

Hello nested interface

As a final thought, can we define a class in an interface?

The answer is yes. When we define a class in an interface, the Java compiler automatically creates a static nested class.

interface M{  
  class A{}  
}  

Tags: Java

Posted by Grisu on Sun, 08 May 2022 22:38:23 +0300