Liên hệ
Ủng hộ, đăng ký theo dõi kênh

Lập trình hướng đối tượng trong Java

Các vấn đề về OOP trong Java như tính đóng gói, kế thừa, đa hình và trừu tượng. Sử dụng các từ khóa extends, interface, implement trong lớp, giao diện

Lập trình hướng đối tượng (OOP) có bốn vấn đề chính: tính đống gói, kế thừa, đa hình và trừu tượng hóa. Ở đây thảo luận về 4 vấn đề đó với Java

Tính đóng gói OOP Java

Ý tưởng của tính đóng gói (Encapsulation) là đảm bảo việc triển khai chi tiết dữ liệu không cần biết bởi người sử dụng. Các biến của một lớp sẽ là ẩn với các lớp khác, truy cập dữ liệu của một lớp chỉ thực hiện thông qua phương thức chứ không truy cập thẳng tới biến. Để truy cập các biến Java cung cấp các hàm public là hàm seter và getter.

Xem lớp ví dụ sau:

class BankAccount {
    private double balance=0;
  public void deposit(double x) {
    if(x > 0) {
      this.balance += x;
    }
  }
}

Lớp trên có biên balance là ẩn với bên ngoài, nó chỉ được truy cập bằng phương thức của lớp là deposite để kiểm tra tính hợp lệ của dữ liệu trước khi thay đổi biến

Một số lợi ích sử dụng tính đóng gói như trên

  • Điều khiển cách lấy và thiết lập dữ liệu của lớp
  • Mềm dẻo hơn và dễ dang thay đổi code
  • Có khả năng thay đổi một phần code mà không ảnh hưởng đến phần khác

Tính kế thừa OOP Java

Tính kế thừa (Inheritance) có nghĩa là một lớp nhận được - có được các thuộc tính, phương thức từ một lớp khác. Lớp nhận được các thuộc tính gọi là lớp con và lớp kia gọi là lớp cha, lớp cơ sở ...

Với Java sử dụng từ khóa extends để khai báo lớp cha

Hãy xem ví dụ sau, xây dựng lớp Animal làm lớp cơ sở

class Animal {
  protected int legs;
  public void eat() {
    System.out.println("Animal eats");
  }
}

Giờ khai báo một lớp có tên Dog kế thừa lớp Animal (thuộc tính và phương thức của Animal sẽ có trong Dog)

class Dog extends Animal {
  Dog() {
    this.legs = 4;
  }
}

Như vậy Dog là lớp con, còn Animal là lớp cha. Thuộc tính legs, phương thức eat tự động kế thừa bởi Dog

Sử dụng

class MyClass {
  public static void main(String[ ] args) {
    Dog d = new Dog();
    d.eat(); //eat kế thừa từ Animal
  }
}

Đọc lại ý nghĩa từ khóa protected tại mục: Modifier

Nên nhớ khởi tạo các lớp không được kế thừa bởi lớp con, tuy nhiên có thể hàm tạo của lớp cha sẽ được gọi khi đối tượng lớp con khởi tạo.

Ví dụ:

class A {
  public A() {
    System.out.println("New A");
  }
}
class B extends A {
  public B() {
    System.out.println("New B");
  }
}

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

/*Outputs
"New A"
"New B"
*/

Ở lớp con, bạn có thể truy cập trực tiếp đến lớp cha mằng từ khóa super, ví dụ super.var truy cập biến var của lớp cha. Một lớp chỉ có thể kế thừa một lớp cha

Tính đa hình OOP Java

Tính đa hình (Polymorphism), ám chỉ tới ý tưởng có nhiều hình dạng, điều này xảy ra khi có một sự kế thừa các lớp có sự liên quan nhau.

Việc gọi một phương thức sẽ có thể có sự khác nhau khi thi hành, nó phụ thuộc vào kiểu đối tượng được gọi.

Hãy xem tính đa hình ở ví dụ sau:

class Animal {
  public void makeSound() {
    System.out.println("Grr...");
  }
}
class Cat extends Animal {
  public void makeSound() {
    System.out.println("Meow");
  }
}
class Dog extends Animal {
  public void makeSound() {
    System.out.println("Woof");
  }
}

Ở ví dụ trên, do Cat và Dog đều kế thừa từ Animal, nến các đối tượng tạo ra bởi Cat, Dog đều là đối tượng Animal. Khi sử dụng có thể code như sau:

public static void main(String[ ] args) {
  Animal a = new Dog();
  Animal b = new Cat();

  a.makeSound();
  //Outputs "Woof"

  b.makeSound();
  //Outputs "Meow"
}

Bạn thấy a, b đều là Animal nhưng khi gọi makeSound() ứng xử là khác nhau, đó là tính đa hình

Nạp chồng Overriding

Ở ví dụ trên ta thấy một lớp con kế thừa các phương thức của lớp cha, nhưng nó vẫn có thể định nghĩa lại cách hoạt động của phương thức nào đó, đó chính là nạp chồng phương thức. Nạp chồng còn gọi với thuật ngữ là Đa hình khi chạy.

Ví dụ

class Animal {
    public void makeSound() {
        System.out.println("Grr...");
    }
}
class Cat extends Animal {
    public void makeSound() {
        System.out.println("Meow");
    }
}

Ta thấy lớp Cat đã định nghĩa lại makeSound() của lớp cha Animal

Các nguyên tắc khi nạp chồng

  • Kiểu trả về và đối số phải giống nhau
  • Phạm vi truy cập (modifier) không được mở rộng hơn lớp cha. Ví dụ lớp cha khai báo là public thì lớp con có thể quá tải là public, private hoặc protected
  • Phương thức final, static không thể nạp chồng
  • Phương thức không thể kế thừa thì không thể nạp chồng
  • Khởi tạo là không thể nạp chồng

Quá tải Overloading

Khi các phương thức có cùng tên nhưng tham số khác nhau thì gọi là sự quá tải phương thức. Khi gọi phương thức, tuy vào tham số và trình biên dịch quyết định gọi phương thức phù hợp

Ví dụ: hai hàm max() định nghĩa sau là quá tải. Khi gọi với tham số kiểu int thì tự gọi hàm thứ nhất, và tham số double thì tự gọi hàm thứ 2

int max(int a, int b) {
  if(a > b) {
    return a;
  }
  else {
    return b;
  }
}
double max(double a, double b) {
  if(a > b) {
    return a;
  }
  else {
    return b;
  }
}

Nạp chồng còn gọi là Đa hình lúc biên dịch

Tính trừu tượng OOP Java

Dữ liệu trừu tượng là cách bao quát thông tin thế giới xung quanh, nó mô ta một cách tổng quát hóa mà không chi tiết. Khái niệm trừu tượng dùng để mô tả cả một tập hợp, loài, dạng ... hơn là một trường hợp cụ thể.

Java trừu tượng hóa thông qua các lớp trừu tượng và các giao diện (interface).

Lớp trừu tượng, phương thức trừu tượng

Một lớp trừu tượng định nghĩa với từ khóa abstract và khi đó:

  • Nếu lớp định nghĩa là abstract thì không thể dùng trực tiếp nó để tạo đối tượng
  • Để sử dụng lớp trừu tượng abstract, bạn phải viết một lớp kế thừa nó
  • Một lớp có chứa hàm abstract thì coi như là lớp abstract

Một phương thức abstract được khai báo mà không có phần {} ví dụ: abstract void walk();

Ví dụ

abstract class Animal {
  int legs = 0;
  abstract void makeSound();
}

Phương thức makeSound(); trên cũng là abstract, lớp kế thừa bắt buộc phải định nghĩa

class Cat extends Animal {
  public void makeSound() {
    System.out.println("Meow");
  }
}

Ta thấy sự trừu tượng hóa của lớp Animal, mọi Animal đều có tiếng kêu, nhưng mỗi lớp kế thừa nó định nghĩa ra một kiểu kêu khác.

Giao diện - interface

Giao diện được tạo ra như lớp với từ khóa interface, nó hoàn toàn giống với lớp abstract chỉ có chứa các phương thức trừu tượng.

Một số tính chất của interface

  • Định nghĩa bằng từ khóa interface
  • Chỉ có thể chứa các biến static, final
  • Không có khởi tạo, vì giao diện không sử dụng trực tiếp tạo ra đối tượng
  • Một interface có thể kế thừa interface khác
  • Một lớp có thể kế thừa nhiều interface

Ví dụ đây là một interface

interface Animal {
  public void eat();
  public void makeSound();
}

Để sử dụng interface bắt buộc lớp phải khai báo với từ khóa implements và định nghĩa các hàm có trong interface

Ví dụ

class Cat implements Animal {
  public void makeSound() {
    System.out.println("Meow");
  }
  public void eat() {
    System.out.println("omnomnom");
  }
}

Vui lòng đăng ký ủng hộ kênh