Trang chủHướng dẫnTìm hiểu Java Inner Class với ví dụ thực tế dễ hiểu
Java

Tìm hiểu Java Inner Class với ví dụ thực tế dễ hiểu

CyStack blog 5 phút để đọc
CyStack blog25/08/2025
Locker Avatar

Bao Tran

Web Developer

Locker logo social
Reading Time: 5 minutes

Trong bài viết này, chúng ta sẽ cùng tìm hiểu Java Inner Class.

Lớp lồng nhau không tĩnh (inner class) trong Java được định nghĩa bên trong phần thân của một lớp khác. Inner class trong Java có thể được khai báo với các mức truy cập private, public, protected hoặc default (mặc định), trong khi outer class (lớp bên ngoài) chỉ có thể được khai báo với mức truy cập public hoặc default. Các lớp lồng nhau (nested classes) trong Java được chia thành hai loại.

Tìm hiểu Java Inner Class

1. Lớp lồng nhau tĩnh (static nested class)

Nếu lớp lồng nhau được khai báo là static, thì nó được gọi là static nested class. Các static nested class chỉ có thể truy cập các thành viên static của lớp bên ngoài. Static nested class giống như bất kỳ lớp cấp cao nhất nào khác và chỉ được lồng vào nhau để thuận tiện cho việc đóng gói. Bạn có thể tạo một đối tượng của static nested class bằng câu lệnh sau:

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

2. Lớp lồng nhau không tĩnh (Inner class)

Bất kỳ lớp lồng nhau nào không có từ khóa static đều được gọi là inner class trong Java. Inner class trong Java có liên kết với đối tượng của lớp bên ngoài và có thể truy cập tất cả các biến và phương thức của lớp bao ngoài. Vì inner class gắn liền với instance (thể hiện) của lớp bên ngoài nên ta không thể khai báo biến static bên trong chúng. Đối tượng của inner class là một phần của đối tượng lớp bên ngoài, do đó để tạo một instance của inner class, trước tiên ta cần tạo một instance của lớp ngoài. Inner class trong Java có thể được khởi tạo theo cách sau;

OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

Có hai dạng đặc biệt của Java inner class.

Local Inner Class (Lớp lồng nhau cục bộ)

Nếu một lớp được định nghĩa bên trong phần thân của một phương thức, thì lớp đó được gọi là local inner class. Vì local inner class không gắn với đối tượng (object), nên không thể sử dụng các modifier như private, public hoặc protected cho nó. Các modifier hợp lệ duy nhất là abstract hoặc final. Local inner class có thể truy cập tất cả các thành viên của lớp bao ngoài, cũng như các biến cục bộ final trong phạm vi phương thức nơi nó được khai báo. Ngoài ra, nó cũng có thể truy cập các biến cục bộ không phải final, nhưng không được phép thay đổi giá trị của các biến này. Vì vậy, nếu bạn chỉ in giá trị của một biến cục bộ không final, thì được phép. Nhưng nếu bạn cố gắng thay đổi giá trị của biến đó bên trong local inner class, chương trình sẽ báo lỗi biên dịch. Local inner class có thể được định nghĩa như sau:

package com.journaldev.innerclasses;

public class MainClass {

	private String s_main_class;

	public void print() {
		String s_print_method = "";
		// local inner class inside the method
		class Logger {
			// able to access enclosing class variables
			String name = s_main_class; 
			// able to access non-final method variables
			String name1 = s_print_method; 

			public void foo() {
				String name1 = s_print_method;
				// Below code will throw compile time error:
				// Local variable s_print_method defined in an enclosing scope must be final or effectively final 
				// s_print_method= ":";
			}
		}
		// instantiate local inner class in the method to use
		Logger logger = new Logger();

	}
}

Chúng ta cũng có thể định nghĩa một local inner class bên trong bất kỳ khối mã nào, chẳng hạn như khối static, khối if-else, v.v. Tuy nhiên, trong trường hợp này, phạm vi (scope) của lớp sẽ rất hạn chế, chỉ tồn tại trong khối mà nó được khai báo.

public class MainClass {

	static {
		class Foo {
			
		}
		Foo f = new Foo();
	}
	
	public void bar() {
		if(1 < 2) {
			class Test {
				
			}
			Test t1 = new Test();
		}
		// Below will throw error because of the scope of the class
		//Test t = new Test();
		//Foo f = new Foo();
	}
}

Lớp lồng nhau ẩn danh (Anonymous Inner Class)

Một local inner class không có tên được gọi là anonymous inner class . Lớp này được định nghĩa và khởi tạo chỉ trong một câu lệnh duy nhất. Nó luôn kế thừa một lớp hoặc triển khai một interface. Vì anonymous classkhông có tên nên không thể định nghĩa constructor (hàm khởi tạo) cho nó. Lớp ẩn danh chỉ có thể truy cập tại đúng vị trí mà nó được định nghĩa. Việc định nghĩa một lớp ẩn danh hơi khó mô tả bằng lời, ta sẽ thấy cách sử dụng thực tế của nó trong chương trình thử nghiệm bên dưới.

Dưới đây là một lớp Java cho thấy cách định nghĩa java inner class, static nested class, local inner class, và anonymous inner class. OuterClass.java

package com.journaldev.nested;

import java.io.File;
import java.io.FilenameFilter;

public class OuterClass {
    
    private static String name = "OuterClass";
    private int i;
    protected int j;
    int k;
    public int l;

    //OuterClass constructor
    public OuterClass(int i, int j, int k, int l) {
        this.i = i;
        this.j = j;
        this.k = k;
        this.l = l;
    }

    public int getI() {
        return this.i;
    }

    //static nested class, can access OuterClass static variables/methods
    static class StaticNestedClass {
        private int a;
        protected int b;
        int c;
        public int d;

        public int getA() {
            return this.a;
        }

        public String getName() {
            return name;
        }
    }

    //inner class, non-static and can access all the variables/methods of the outer class
    class InnerClass {
        private int w;
        protected int x;
        int y;
        public int z;

        public int getW() {
            return this.w;
        }

        public void setValues() {
            this.w = i;
            this.x = j;
            this.y = k;
            this.z = l;
        }

        @Override
        public String toString() {
            return "w=" + w + ":x=" + x + ":y=" + y + ":z=" + z;
        }

        public String getName() {
            return name;
        }
    }

    //local inner class
    public void print(String initial) {
        //local inner class inside the method
        class Logger {
            String name;

            public Logger(String name) {
                this.name = name;
            }

            public void log(String str) {
                System.out.println(this.name + ": " + str);
            }
        }

        Logger logger = new Logger(initial);
        logger.log(name);
        logger.log("" + this.i);
        logger.log("" + this.j);
        logger.log("" + this.k);
        logger.log("" + this.l);
    }

    //anonymous inner class
    public String[] getFilesInDir(String dir, final String ext) {
        File file = new File(dir);
        //anonymous inner class implementing FilenameFilter interface
        String[] filesList = file.list(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(ext);
            }

        });
        return filesList;
    }
}

Dưới đây là chương trình thử nghiệm cho thấy cách khởi tạo và sử dụng inner class trong Java: InnerClassTest.java

package com.journaldev.nested;

import java.util.Arrays;
//nested classes can be used in import for easy instantiation
import com.journaldev.nested.OuterClass.InnerClass;
import com.journaldev.nested.OuterClass.StaticNestedClass;

public class InnerClassTest {

    public static void main(String[] args) {
        OuterClass outer = new OuterClass(1,2,3,4);
        
        //static nested classes example
        StaticNestedClass staticNestedClass = new StaticNestedClass();
        StaticNestedClass staticNestedClass1 = new StaticNestedClass();
        
        System.out.println(staticNestedClass.getName());
        staticNestedClass.d=10;
        System.out.println(staticNestedClass.d);
        System.out.println(staticNestedClass1.d);
        
        //inner class example
        InnerClass innerClass = outer.new InnerClass();
        System.out.println(innerClass.getName());
        System.out.println(innerClass);
        innerClass.setValues();
        System.out.println(innerClass);
        
        //calling method using local inner class
        outer.print("Outer");
        
        //calling method using anonymous inner class
        System.out.println(Arrays.toString(outer.getFilesInDir("src/com/journaldev/nested", ".java")));
        
        System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/journaldev/nested", ".class")));
    }

}

Dưới đây là kết quả đầu ra của chương trình ví dụ về Java inner class ở trên.

OuterClass
10
0
OuterClass
w=0:x=0:y=0:z=0
w=1:x=2:y=3:z=4
Outer: OuterClass
Outer: 1
Outer: 2
Outer: 3
Outer: 4
[NestedClassTest.java, OuterClass.java]
[NestedClassTest.class, OuterClass$1.class, OuterClass$1Logger.class, OuterClass$InnerClass.class, OuterClass$StaticNestedClass.class, OuterClass.class]

Lưu ý rằng khi biên dịch OuterClass, các file class riêng biệt sẽ được tạo ra cho inner class, local inner class và static nested class.

Lợi ích của Java inner class

  1. Nếu một lớp chỉ hữu ích đối với duy nhất một lớp khác, thì việc lồng nó bên trong và giữ chúng cùng nhau là hợp lý. Điều này giúp tổ chức đóng gói mã nguồn một cách gọn gàng hơn.
  2. Java inner class hỗ trợ tính đóng gói (encapsulation). Lưu ý rằng inner class có thể truy cập các thành viên private của lớp bên ngoài, đồng thời chúng ta cũng có thể ẩn inner class khỏi thế giới bên ngoài.
  3. Việc giữ các lớp nhỏ nằm bên trong lớp cấp cao giúp mã nguồn gần gũi hơn với nơi nó được sử dụng, từ đó làm cho mã dễ đọc hơn và dễ bảo trì hơn.

Vậy là chúng ta đã tìm hiểu xong về Java inner class.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất