Java – Inner class

Java inner class là class được định nghĩa bên trong class khác. Java inner class có thể được khai báo là private, public, protected, hoặc với truy cập mặc định trong khi class bên ngoài có thể chỉ có truy cập public hoặc mặc định.

Các class lồng nhau trong Java được chia thành 2 kiểu:

  1.  Static nested class : Nếu các class lồng nhau là static thì nó được gọi là static nested class. Static nested class có thể chỉ truy cập thành phần static của class bên ngoài. Static nested class giống như bất kỳ class cao cấp nào khác và được lồng vào nhau để thuận tiện cho việc đóng gói. Một static class object có thể được tạo bằng cách sử dụng câu lệnh sau đây
    OuterClass.StaticNestedClass nestedObject =
         new OuterClass.StaticNestedClass();
  2.  Java inner class: Bất kỳ class lồng nhau nào mà không phải staic thì được hiểu là inner class. Java inner class được liên kết với object của class và chúng có thể truy cập đến tất cả các biến và phương thức của class bên ngoài. Do inner class được liên kết với instance nên chúng không có bất kỳ biến static nào bên trong. Object của inner class là một phần của object của class bên ngoài. Đầu tiên chúng ta cần tạo object của class bên ngoài trước.Inner class có thể được khởi tạo như sau:
    OuterClass outerObject = new OuterClass();
    OuterClass.InnerClass innerObject = outerObject.new InnerClass();

Có 2 kiểu đặc biệt của inner class

local inner class

Nếu một class được định nghĩa bên trong một phương thức thì được gọi là local inner class

Vì local inner class không liên kết với object, nên chúng ta không thể sử dụng truy cập private, public hoặc protected với nó. Modifier được cho phép chỉ có thể là abstract hoặc final

Local inner class có thể truy cập đến toàn bộ thành phần của class kèm theo và các biến local là final trong phạm vi của nó. Ngoài ra, nó có thể truy cập các biến local không phải là final của phương thức mà nó được định nghĩa. Nhưng nó không thể thay đổi giá trị của chúng. Do đó nếu bạn muốn in ra giá trị của các biến local không phải là final thì được phép nhưng nếu bạn muốn thay đổi giá trị của chúng thì bạn sẽ gặp lỗi khi biên dịch.

Local inner class có thể được định nghĩa như sau

package com.example.innerclasses;

public class MainClass {
  private String s_main_class;

  public void print() {
    String s_print_method = "";
    // local inner class bên trong phương thức
    class Logger {
      // có thể truy cập các biến class kèm theo
      String name = s_main_class; 
      // có thể truy cập các biến không phải final
      String name1 = s_print_method; 

      public void foo() {
        String name1 = s_print_method;
        // code bên dưới sẽ đưa ra một lỗi khi biên dịch
        // biến local s_print_method được định nghĩa trong phạm vi đính kèm phải là final 
        // s_print_method= ":";
      }
    }
    // khởi tạo local inner class trong phương thức sử dụng
    Logger logger = new Logger();
  }
}

Chúng ta có thể định nghĩa một local inner class trong một block ví dụ như là static block, if-else block… Tuy nhiên trong trường hợp này phạm vi của class là tương đối giới hạn.

Chú ý block ở đây nghĩa là trong đoạn code bắt đầu bằng { và kết thúc }

public class MainClass {
  static {
    class Foo {

    }
    Foo f = new Foo();
  }
	
  public void bar() {
    if(1 < 2) {
      class Test {
				
      }
      Test t1 = new Test();
    }
    // đoạn code bên dưới sẽ lỗi bởi vì giới hạn của class
    //Test t = new Test();
    //Foo f = new Foo();
  }
}

Inner class anonymous (vô danh)

Một local inner class không có tên thì được gọi là inner class vô danh. Một class vô danh được định nghĩa và khởi tạo trong một câu lệnh duy nhất.

Inner class thường extend từ một class hoặc thực thi cho một interface. Bởi vì class vô danh không có tên nên không thể định nghĩa constructor cho class vô danh.

Inner class vô danh chỉ có thể truy cập tại điểm nơi nó được định nghĩa. Nó hơi khó để định nghĩa làm thể nào để tạo một inner class vô danh, chúng ta hãy cùng xem các sử dụng nó trong thực tế thông qua ví dụ bên dưới đây

Ví dụ bên dưới đây sẽ trình bày cách chúng ta tạo một inner class, static nested class, local inner class và inner class vô danh

OuterClass.java

package com.example.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, có thể truy cập các biến/phương thức static của OuterClass
  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, không phải là static và có thể truy cập tất cả các biến/phương thức của 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 bên trong phương thức
    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);
  }

  //inner class vô danh
  public String[] getFilesInDir(String dir, final String ext) {
    File file = new File(dir);
    //inner class vô danh thực thi FilenameFilter interface
    String[] filesList = file.list(new FilenameFilter() {
      @Override
      public boolean accept(File dir, String name) {
        return name.endsWith(ext);
      }
    });
    return filesList;
  }
}

Tiếp theo chúng ta thử viết một chương trình để test đoạn code bên trên

InnerClassTest.java

package com.example.nested;

import java.util.Arrays;
//nested classes có thể được sử dụng trong import để dễ dàng khởi tạo
import com.example.nested.OuterClass.InnerClass;
import com.example.nested.OuterClass.StaticNestedClass;

public class InnerClassTest {

  public static void main(String[] args) {
    OuterClass outer = new OuterClass(1,2,3,4);
        
    // ví dụ static nested classes
    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);
        
    //ví dụ inner class
    InnerClass innerClass = outer.new InnerClass();
    System.out.println(innerClass.getName());
    System.out.println(innerClass);
    innerClass.setValues();
    System.out.println(innerClass);
        
    //gọi phương thức sử dụng local inner class
    outer.print("Outer");
        
    //Gọi phương thức sử dụng inner class vô danh
    System.out.println(Arrays.toString(outer.getFilesInDir("src/com/example/nested", ".java")));
        
    System.out.println(Arrays.toString(outer.getFilesInDir("bin/com/example/nested", ".class")));
  }
}

Kết quả

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]

Ưu điểm inner class

  1. Nếu một class chỉ hữu ích cho một class, ngoài ra có ý nghĩa để giúp các class được lồng nhau và đặt cùng nhau. Nó giúp cho việc đóng gói class
  2. Java inner class thực hiện đóng gói. Chú ý rằng các inner class có thể truy cập thành phần private của class bên ngoài và đồng thời chúng ta có thể ẩn inner class với thế giới bên ngoài
  3. Giúp cho class trở nên nhỏ gọn hơn bên trong các class lớp cao nhất, đặt code gần hơn nơi sử dụng chúng, giúp tăng khả năng duy trì và dễ đọc hơn.

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

Your email address will not be published.