1. Từ khóa this trong Java là gì?

Từ khóa this hay con trỏ this trong Java là một trong những khái niệm cơ bản và quan trọng khi làm việc với đối tượng và lớp. Nó chính là một biến tham chiếu được sử dụng để tham chiếu tới đối tượng của lớp hiện tại. Biến this là một biến ẩn tồn tại trong tất cả các lớp trong ngông ngữ Java. Một class trong Java luôn tồn tại một biến this.

Ta có thể hiểu trong tiếng việc this là “cái này” còn trong lập trình thì nó nghĩa là đối tượng này. Nó tham chiếu ngược lại đến đối tượng, giúp ta có thể truy xuất đến các giá trị của đối tượng đó.

Trong Java có một số cách sử dụng this như sau:

  • Sử dụng để tham chiếu biến instance của lớp
  • Sử dụng để triệu hồi Constructor của lớp hiện tại
  • Sử dụng để triệu hồi ngầm định phương thức lớp hiện tại
  • This có thể được truyền như là một tham số trong lời gọi phương thức
  • This có thể được truyền như là một tham số trong lời gọi Constructor
  • This cũng có thể được sử dụng để trả về instance của lớp hiện tại

Ví dụ:

class Main {
    private int a;
    Main(int b){
        this.a = b;
        System.out.println(this.a);
        System.out.println(this);
    }
    public static void main(String[] args) {
        Main c = new Main(325);
        System.out.println(c);
    }
}

Kết quả

325
Main@2ff4acd0
Main@2ff4acd0

Trong ví dụ trên, chúng ta đã tạo một đối tượng có tên là c của lớp Main. Sau đó, chúng ta in ra tham chiếu đến đối tượng cthis của lớp Main. Ở đây, chúng ta có thể thấy rằng tham chiếu của cả cthis đều giống nhau. Nghĩa là this chính là đối tượng c.

2. Sử dụng this tham chiếu tới biến instance của lớp hiện tại

Trong Java, không được phép khai báo hai hoặc nhiều biến có cùng tên trong một phạm vi (phạm vi lớp hoặc phạm vi phương thức). Tuy nhiên, các biến và các tham số sẽ có thể có cùng tên.

Đây là cách mà từ khóa this giúp ta phân biệt giữa biến toàn cục và tham số khi tên của chúng hoàn toàn giống nhau. Điều này thể hiện rõ ràng nhất thông qua Constuctor. Ngoài ra cũng là để phân biệt đâu là biến và đâu là thuộc tính của lớp khi chúng trùng tên với nhau.

Ví dụ:

public class Main {
    int a;
    int b;

    // Hàm constructor chứa tham số
    Main(int a, int b) {
        this.a = a;
        this.b = b;
    }

    void display() {
    // Hiển thị giá trị của biến a và b
        System.out.println("a = " + a + "\nb = " + b);
    }

    public static void main(String[] args) {
        Main object = new Main(1, 99);
        object.display();
    }
}

Kết quả

a = 1
b = 99

Ở đây biến a và biến b đặt ở bên ngoài hàm Main có tên hoàn toàn giống tham số được truyền vào. Tuy nhiên, khi gọi this.a thì Java sẽ hiểu là nó cần gọi đến biến a có trong bối cảnh (context) hiện tại. Trong trường hợp này, this.a = a sẽ tương đương với this.a = 1. Do đó, biến a sẽ được gán giá trị 1 khi chạy chương trình. Tương tự như vậy đối với this.b = b

Ví dụ 2:

  • Không sử dụng this
class Main {
    private int a;
    Main(int a){
        a = a;
    }
    public static void main(String[] args) {
        Main c = new Main(325);
        System.out.println(c.a);
    }
}

Kết quả

0

Trong ví dụ trên, chúng ta đã truyền 325 làm giá trị tham số cho hàm tạo. Tuy nhiên, chúng ta nhận được kết quả là 0. Điều này là do trình biên dịch Java bị nhầm lẫn vì sự không rõ ràng trong tên biến của lớp và tham số của hàm tạo Main. Ngoài ra, nếu tên của tham số và tên biến của lớp là khác nhau, trình biên dịch sẽ tự động thêm con trỏ this cho biến của lớp.

  • Sử dụng this
class Main {
    private int a;
    Main(int b){
        this.a = b;
    }
    public static void main(String[] args) {
        Main c = new Main(325);
        System.out.println(c.a);
    }
}
  • Đoạn mã này tương tự với đoạn mã trên
class Main {
    private int a;
    Main(int b){
        a = b;
    }
    public static void main(String[] args) {
        Main c = new Main(325);
        System.out.println(c.a);
    }
}

Kết quả

325

3. Sử dụng this gọi Constructor của lớp hiện tại

Cách này được ưu tiên sử dụng nếu chương trình có nhiều Constructor và có nhu cầu sử dụng lại. Tại sao lại như vậy? Vì khi làm việc với Constructor chúng ta có thể gọi Constructor từ Constructor khác. Trường hợp như vậy ta sẽ không thể gọi hàm tạo một cách rõ ràng. Lúc này có khả năng Constructor nhiều tham số hơn sẽ cần gọi tới Constructor ít tham số hơn. Với trường hợp này thì this như là một hàm nên chúng ta phải sử dụng this dưới dạng this() hoặc this(tham_số)

Ví dụ:

public class Main {
    int id;
    String name;
 
    Main() {
        System.out.println("Gọi Constructor mặc định");
    }
 
    Main(int id, String name) {
        this(); // nó được sử dụng để gọi Constructor của lớp hiện tại
        this.id = id;
        this.name = name;
    }
 
    void display() {
        System.out.println(id + " " + name);
    }
 
    public static void main(String args[]) {
        Main e1 = new Main(111, "Viet");
        Main e2 = new Main(222, "Nam");
        e1.display();
        e2.display();
    }
}

Kết quả

Gọi Constructor mặc định
Gọi Constructor mặc định
111 Viet
222 Nam

Ví dụ 2: dùng this để sử dụng lại Constructor trong Constructor khác. Nó duy trì 1 chuỗi các Constructor

public class Main {
    int id;
    String name;
    String city;
 
    Main(int id, String name) {
        this.id = id;
        this.name = name;
    }
 
    Main(int id, String name, String city) {
        this(id, name);// bây giờ không cần khởi tạo id và name
        this.city = city;
    }
 
    void display() {
        System.out.println(id + " " + name + " " + city);
    }
 
    public static void main(String args[]) {
        Main e1 = new Main(111, "Viet");
        Main e2 = new Main(222, "Nam", "Ha Noi");
        e1.display();
        e2.display();
    }
}

Kết quả

111 Viet null
222 Nam Ha Noi

Chú ý

This chỉ được dùng trong các Constructor, nếu dùng this trong các phương thức bình thường khác thì bị báo lỗi. Và nếu muốn sử dụng this thì this phải là dòng code đầu tiên bên trong một Constructor.

4. Dùng this gọi phương thức lớp hiện tại

Ta có thể sử dụng từ khóa this để gọi phương thức của lớp hiện tại. Nếu không sử dụng từ khóa this, trình biên dịch sẽ tự động thêm từ khóa this cho việc gọi phương thức.

Ví dụ:

public class Main {
    void m() {
        System.out.println("Gọi phương thức bằng từ khóa this");
    }
 
    void n() {
        this.m();
    }
 
    void p() {
        n();// trình biên dịch sẽ thêm this để gọi phương thức n() như this.n()
    }
 
    public static void main(String args[]) {
        Main o1 = new Main();
        o1.p();
    }
}

Kết quả

Gọi phương thức bằng từ khóa this

5. Dùng this như một tham số của phương thức

Từ khóa this có thể được dùng như một tham số trong phương thức. Cách dùng này chủ yếu được sử dụng trong xử lý sự kiện(event).

public class Main {

    void m(Main obj) {
        System.out.println("Dùng this như một tham số");
    }

    void p() {
        m(this); // this lúc này là đối tượng Main
    }

    public static void main(String args[]) {
        Main main = new Main();
        main.p();
    }
}

Kết quả

Dùng this như một tham số

Chúng ta cũng có thể truyền từ khóa this trong Constructor. Việc này rất hữu ích nếu chúng ta phải sử dụng một đối tượng trong nhiều lớp.

class Main {

    A4 obj;

    Main(A4 obj) {
        this.obj = obj;
    }

    void display() {
        System.out.println(obj.data);// sử dụng biến thành viên cửa lớp A4
    }
}

class A4 {

    int data = 10;

    A4() {
        Main main = new Main(this);
        main.display();
    }

    public static void main(String args[]) {
        A4 a = new A4();
    }
}

Kết quả

10

6. Dùng this với các phương thức Getters và Setters

Một cách sử dụng phổ biến khác của con trỏ this là trong các phương thức settersgetters của một lớp.

Ví dụ:

class Main {
    private int a;
    void setA(int a) {
        this.a = a;
    }
    int getA(){
        return this.a;
    }
    public static void main(String[] args) {
        Main c = new Main();
        c.setA(1000);
        System.out.println(c.getA());
    }
}

Kết quả

1000

7. Dùng this như một tham số của Construct

Tính năng này trong thực tế rất hữu ích, nhất là với các hàm Constructor được sử dụng nhiều lần.

Ví dụ:

public class Main {

    int x = 100;

    // Hàm constructor tạo ra đối tượng A
    // sau đó chuyển nó thành đối số trong hàm constructor
    Main() {
        A obj = new A(this);
    }

    // phương thức hiện thị giá trị của x
    void display() {
        System.out.println("Giá trị của x trong lớp B là: " + x);
    }
    class A {
        Main obj;

        // Phương thức khởi tạo tham số với dối tượng B
        A(Main obj) {
            this.obj = obj;
            // gọi phương thức display của lớp B
            obj.display();
        }
    }

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

Kết quả

Giá trị của x trong lớp B là: 100