Từ khóa this và super trong Java

Từ khóa this trong java

Từ khóa this trong java 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.

Từ khóa this có 6 cách sử dụng sau:

  • Tham chiếu tới biến instance của lớp hiện tại.
  • Gọi phương thức (method) của lớp hiện tại.
  • Gọi hàm dựng (constructor) của lớp hiện tại.
  • Trả về instance của lớp hiện tại
  • Được truyền như một tham số trong phương thức (method).
  • Được truyền như một tham số trong hàm dựng (constructor).

Tham chiếu tới biến của lớp hiện tại.

Từ khóa this trong java có thể được dùng để tham chiếu tới biến instance của lớp hiện tại.

Ví dụ:

package com.maixuanviet.oop;
 
public class UsingThisExample {
     
    private int id;
     
    private String website;
     
    private String subject;
     
    public UsingThisExample(String website, String subject) {
        website = website;
        subject = subject;
    }
     
    public void print() {
        System.out.println("Id = " + id);
        this.printWebsite();
        this.printSubject();
    }
     
    private void printWebsite() {
        System.out.println("Subject = " + subject);
    }
     
    private void printSubject() {
        System.out.println("Website = " + website);
    }
     
    public static void main(String[] args) {
        UsingThisExample ex1 = new UsingThisExample("maixuanviet.com", "OOP");
        ex1.print();
    }
     
}

Kết quả:

Id = 0
Subject = null
Website = null

Như chúng ta thấy, gía trị của biến được gán trong hàm construct không có tác dụng, do tên thuộc tính và tên biến giống nhau.
Để giải quyết vấn đề này ta sử dụng từ khóa this như ví dụ sau:

package com.maixuanviet.oop;
 
public class UsingThisExample {
     
    private int id;
     
    private String website;
     
    private String subject;
     
    public UsingThisExample(String website, String subject) {
        this.website = website;
        this.subject = subject;
    }
     
    public void print() {
        System.out.println("Id = " + id);
        this.printWebsite();
        this.printSubject();
    }
     
    private void printWebsite() {
        System.out.println("Subject = " + subject);
    }
     
    private void printSubject() {
        System.out.println("Website = " + website);
    }
     
    public static void main(String[] args) {
        UsingThisExample ex1 = new UsingThisExample("maixuanviet.com", "OOP");
        ex1.print();
    }
     
}

Kết quả:

Id = 0
Subject = OOP
Website = maixuanviet.com

Nếu biến cục bộ và biến toàn cục có tên khác nhau thì không cần sử dụng từ khóa this. Tuy nhiên, nên sử dụng từ khóa this để chương trình được rõ ràng và dễ hiểu.

Ví dụ:
Persion.java

package com.maixuanviet.oop;
 
public class Person {
    public void print() {
        System.out.println("This is parent class");
    }
}

Student.java

package com.maixuanviet.oop;
 
public class Student extends Person {
    private int id;
    private String name;
 
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
 
    public void print() {
        System.out.println("id = " + id + ", name = " + name);
    }
 
    public void printChild1() {
        this.print();
    }
 
    public void printChild2() {
        super.print();
    }
 
    public static void main(String args[]) {
        Student student = new Student(1, "maixuanviet");
        student.print();
        System.out.println("---");
        student.printChild1();
        System.out.println("---");
        student.printChild2();
    }
 
}

Kết quả:

id = 1, name = gpcoder
---
id = 1, name = gpcoder
---
This is parent class

Như ví dụ trên, rõ ràng là trong trường hợp mà chương trình của bạn có nhiều class, các class có sử dụng kế thừa thì việc để từ khóa this sẽ giúp chương trình của bạn rõ ràng hơnc hạn chế sai sót do không xác định được đang gọi phương thức ở lớp cha hay lớp hiện tại.

1.2. Gọi phương thức của lớp hiện tại.

Chúng 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ụ:

package com.maixuanviet.oop;
 
public class UsingThisExample {
     
    private int id;
     
    private String website;
     
    private String subject;
     
    public UsingThisExample(String website, String subject) {
        this.website = website;
        this.subject = subject;
    }
     
    public void print() {
        System.out.println("Id = " + id);
        this.printWebsite();
        printSubject();
    }
     
    private void printWebsite() {
        System.out.println("Subject = " + subject);
    }
     
    private void printSubject() {
        System.out.println("Website = " + website);
    }
     
    public static void main(String[] args) {
        UsingThisExample ex1 = new UsingThisExample("maixuanviet.com", "OOP");
        ex1.print();
    }
     
}

Kết quả:

Id = 0
Subject = OOP
Website = maixuanviet.com

Như ví dụ trên, từ khóa this được sử dụng để gọi phương thức this.printWebsite(). Phương thức printSubject() trình biên dịch sẽ tự động thêm từ khóa this cho việc gọi phương thức.

1.3. Gọi Constructor của lớp hiện tại.

Phương thức this() có thể được sử dụng để gọi constructor của lớp hiện tại. Cách sử dụng này sẽ hữu dụng hơn nếu bạn có nhiều constructor trong một lớp và bạn muốn sử dụng lại constructor.

Phương thức this() phải được khai báo dòng lệnh đầu tiên trong constructor.

Ví dụ:

package com.maixuanviet.oop;
 
public class UsingThisExample {
 
    private int id;
 
    private String website;
 
    private String subject;
 
    public UsingThisExample() {
        this.id = 1;
        this.website = "https://www.maixuanviet.com";
    }
 
    public UsingThisExample(String website ) {
        this(); // Bắt buộc phải dòng lệnh đầu tiên trong constructor
        this.website = website ;
    }
 
    public UsingThisExample(String website, String subject) {
        this(website); // Bắt buộc phải dòng lệnh đầu tiên trong constructor
        this.subject = subject;
    }
 
    public void print() {
        System.out.println("Id = " + id);
        this.printWebsite();
        this.printSubject();
    }
 
    private void printWebsite() {
        System.out.println("Subject = " + subject);
    }
 
    private void printSubject() {
        System.out.println("Website = " + website);
    }
 
    public static void main(String[] args) {
        UsingThisExample ex1 = new UsingThisExample("maixuanviet.com", "OOP");
        ex1.print();
    }
 
}

Kết quả:

Id = 1
Subject = OOP
Website = maixuanviet.com

1.4. Trả về instance của lớp hiện tại

Chúng ta có thể trả về instance của lớp hiện tại bằng cách sử dụng từ khóa this. Trong trường hợp này, kiểu trả về của phương thức phải là class của lớp hiện tại.
Ví dụ:

package com.maixuanviet.oop;
 
public class UsingThisExample {
 
    private int id;
 
    private String website;
 
    private String subject;
 
    public UsingThisExample() {
        this.id = 1;
    }
 
    public UsingThisExample setWebsite(String website) {
        this.website = website;
        return this;
    }
 
    public UsingThisExample setSubject(String subject) {
        this.subject = subject;
        return this;
    }
 
    public void print() {
        System.out.println("Id = " + id);
        this.printWebsite();
        this.printSubject();
    }
 
    private void printWebsite() {
        System.out.println("Subject = " + subject);
    }
 
    private void printSubject() {
        System.out.println("Website = " + website);
    }
 
    public static void main(String[] args) {
        UsingThisExample ex1 = new UsingThisExample()
                .setSubject("OOP")
                .setWebsite("maixuanviet.com");
        ex1.print();
    }
 
}

Kết quả:

Id = 1
Subject = OOP
Website = maixuanviet.com

Như ví dụ trên, phương thức setWebsite và setSubject trả về tham chiếu tới biến instance của lớp hiện tại.

1.5. Được truyền như một tham số trong phương thức (method).

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

Ví dụ:

Helper.java

public class Helper {
     
    public void print(UsingThisExample ex) {
        System.out.println("Id = " + ex.getId());
        System.out.println("Website = " + ex.getWebsite());
    }
     
}

UsingThisExample.java

public class UsingThisExample {
    private int id;
    private String website;
     
    UsingThisExample () {
        this.id = 1;
        this.website = "gpcoder";
    }
     
    public void print() {
        Helper helper = new Helper();
        helper.print(this); 
    }
 
    public int getId() {
        return id;
    }
 
    public String getWebsite() {
        return website;
    }
     
    public static void main(String[] args) {
        UsingThisExample ex = new UsingThisExample();
        ex.print();
    }
}

Kết quả:

Id = 1
Website = maixuanviet

Như ví dụ trên, phương thức print của lớp UsingThisExample truyền tham số là this (tham chiếu biến instance của lớp UsingThisExample) sang cho phương thức print của lớp Helper xử lý.

1.6. Được truyền như một tham số trong hàm dựng (constructor).

Từ khóa this có thể được dùng như một tham số trong constructor. Cách dùng này rất hữu ích nếu chúng ta sử dụng một đối tượng trong nhiều lớp.

Ví dụ:
Helper.java

public class Helper {
     
    private UsingThisExample ex;
     
    public Helper(UsingThisExample ex) {
        this.ex = ex;
    }
     
    public void printId() {
        System.out.println("Id = " + ex.getId());
    }
     
    public void printWebsite() {
        System.out.println("Website = " + ex.getWebsite());
    }
     
}

UsingThisExample.java

public class UsingThisExample {
    private int id;
    private String website;
     
    UsingThisExample () {
        this.id = 1;
        this.website = "maixuanviet";
    }
     
    public void print() {
        Helper helper = new Helper(this);
        helper.printId();   
        helper.printWebsite();
    }
 
    public int getId() {
        return id;
    }
 
    public String getWebsite() {
        return website;
    }
     
    public static void main(String[] args) {
        UsingThisExample ex = new UsingThisExample();
        ex.print();
    }
}

Kết quả:

Id = 1
Website = maixuanviet

Như ví dụ trên, phương thức print gọi hàm khởi tạo của lớp Helper với tham số là this (tham chiếu biến instance của lớp UsingThisExample), sau đó gọi hàm printId và printWebsite để xử lý. Cách này hữu ích khi cần tái sử dụng object ở nhiều phương thức khác nhau, trong ví dụ này là printId và printWebsite.

2. Từ khóa super trong java

Từ khóa super trong java là một biến tham chiếu được sử dụng để tham chiếu trực tiếp đến đối tượng của lớp cha gần nhất.

Bất cứ khi nào bạn tạo ra instance (thể hiện) của lớp con, một instance của lớp cha được tạo ra ngầm định, nghĩa là được tham chiếu bởi biến super.

Từ khóa super có 3 cách sử dụng sau:

  • Gọi trực tiếp hàm dựng (constructor) của lớp cha gần nhất.
  • Gọi trực tiếp thuộc tính (field) của lớp cha gần nhất.
  • Gọi trực tiếp phương thức (method) của lớp cha gần nhất.

 2.1. Gọi trực tiếp constructor của lớp cha gần nhất.

Ví dụ:

Parent.java

public class Parent {
     
    private String website;
     
    public Parent() {
        System.out.println("This is parent");
        print();
    }
     
    public Parent(String website) {
        this.website = website;
        System.out.println("This is parent");
        print();
    }
     
    public void print() {
        System.out.println("Website = " + website);
    }
}

Child.java

public class Child extends Parent {
 
    public Child() {
        System.out.println("This is child");
    }
 
    public Child(String website) {
        super(website);
        System.out.println("This is child");
    }
     
    public static void main(String[] args) {
        Child child1 = new Child();
        System.out.println("---");
        Child child2 = new Child("maixuanviet.com");
    }
}

Kết quả:

This is parent
Website = null
This is child
---
This is parent
Website = gpcoder.com
This is child

Như ví dụ trên:

  • Trong hàm mainchild1 gọi hàm khởi tạo không có tham số, hàm khởi tạo Child() không gọi super(), khi đó trình biên dịch sẽ tự động thêm super() vào hàm constructor để gọi khởi tạo ở lớp cha.
  • Trong hàm mainchild2 gọi hàm khởi tạo có tham số, hàm khởi tạo Child(str) gọi hàm super() để gọi khởi tạo ở lớp cha có tham số.

2.2. Gọi trực tiếp biến của lớp cha gần nhất.

Ví dụ:

Parent.java

public class Parent {
     
    public String website = "maixuanviet.com";
    public String subject = "OOP";
     
    public Parent() {
         
    }
}

Child.java

public class Child extends Parent {
     
    public String website = "https://www.maixuanviet.com";
     
    public Child() {
         
    }
     
    public void printParent() {
        System.out.println("Short link: " + super.website);
        System.out.println("Subject " + subject);
    }
     
    public void printChild() {
        System.out.println("Full link: " + website);
        System.out.println("Subject " + subject);
    }
     
    public static void main(String[] args) {
        Child child = new Child();
        child.printParent();
        System.out.println("---");
        child.printChild();
    }
}

Kết quả:

Short link: maixuanviet.com
Subject OOP
---
Full link: https://www.maixuanviet.com
Subject OOP

Như ví dụ trên:

  • Phương thức printParent() sử dụng super để sử dụng biến website của lớp Parent, do lớp Child có biến website cùng tên với lớp Parent. Nếu không gọi super, như phương thức printChild thì sẽ gọi biến website của lớp Child.
  • Trường hợp lớp Child không có biến trùng tên với lớp cha thì có thể không cần sử dụng từ khóa super. Trong ví dụ trên là biến subject, ở lớp Child không có biến này nên không cần sử dụng từ khóa super.

2.3. Gọi trực tiếp phương thức (method) của lớp cha gần nhất.

Ví dụ:

Parent.java

public class Parent {
     
    private String website;
     
    public Parent(String website) {
        this.website = website;
    }
     
    public void print() {
        System.out.println("Website = " + website);
    }
     
    public void welcome() {
        System.out.println("Welcome to maixuanviet.com");
    }
}

Child.java

public class Child extends Parent {
     
    public Child(String website) {
        super(website);
    }
 
    public void printChild1() {
        print();
    }
 
    public void printChild2() {
        super.print();
        welcome();
    }
     
    public void print() {
        System.out.println("Subject = OOP");    
    }
     
    public static void main(String[] args) {
        Child child = new Child("maixuanviet.com");
        child.printChild1();
        System.out.println("---");
        child.printChild2();
    }
}

Kết quả:

Subject = OOP
---
Website = maixuanviet.com
Welcome to maixuanviet.com

Như ví dụ trên:

  • Phương thức printChild2() sử dụng super để gọi phương thức print của lớp Parent, do lớp Child đã ghi đè (override) lại phương thức của lớp cha. Nếu không gọi super như phương thức printChild1 thì sẽ gọi hàm print của lớp Child.
  • Trường hợp lớp Child không ghi đè (override) lại phương thức của lớp cha thì có thể không cần sử dụng từ khóa super. Trong ví dụ trên là phương thức welcome(), ở lớp Child không có viết lại phương thức này.