CodeGym /Các khóa học /JAVA 25 SELF /Các lớp và phương thức trừu tượng: cú pháp, ví dụ

Các lớp và phương thức trừu tượng: cú pháp, ví dụ

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Cú pháp của lớp trừu tượng

Hãy cùng làm rõ lớp trừu tượng trong Java là gì và vì sao cần nó. Hãy hình dung bạn có một bộ LEGO: bạn có một tập các mảnh ghép (ví dụ, “bánh xe”, “viên gạch”), và có những mảnh đặc thù cho từng mô hình. Lớp trừu tượng giống như một hướng dẫn tổng quát về cách làm việc với các mảnh ghép mà không mô tả việc lắp ráp một mô hình cụ thể: gạch khớp với nhau bằng ngàm, bánh xe gắn vào trục, các mảnh có thể chồng lên nhau theo lớp. Lớp trừu tượng mô tả các quy tắc chung và các bước bắt buộc này, nhưng không trình bày việc lắp mô hình cụ thể. Các mô hình cụ thể chính là các lớp con: chúng lấy hướng dẫn chung và bổ sung những bước còn thiếu.

Trong Java, lớp trừu tượng là một lớp không thể được tạo trực tiếp (không thể gọi new AbstractClass()), nhưng có thể kế thừa từ nó và triển khai các phương thức “chưa viết xong”.

Lớp trừu tượng phù hợp khi:

  • Một nhóm đối tượng có hành vi hoặc trạng thái chung, nhưng một phần logic khác nhau.
  • Bạn muốn triển khai một phần chức năng “mặc định”, còn phần khác để lớp con tự triển khai.
  • Bạn muốn cấm tạo đối tượng của lớp này trực tiếp (ví dụ, “Động vật” tự nó thì không xuất hiện, nhưng “Mèo” — thì có).

Cách khai báo lớp trừu tượng

Rất đơn giản: đặt từ khóa class sau từ khóa abstract.

public abstract class Animal {
    // Trường (ví dụ: tên của động vật)
    protected String name;

    // Constructor
    public Animal(String name) {
        this.name = name;
    }

    // Phương thức trừu tượng — chỉ khai báo, không có phần triển khai!
    public abstract void makeSound();

    // Phương thức thông thường (đã được triển khai)
    public void sleep() {
        System.out.println(name + " đang ngủ: Zzz...");
    }
}

Đặc điểm:

  • Lớp trừu tượng có thể chứa cả phương thức đã triển khai và phương thức trừu tượng.
  • Lớp trừu tượng có thể chứa trường, constructor và thậm chí cả các phương thức static.
  • Không thể tạo đối tượng của lớp trừu tượng trực tiếp:
  • Animal a = new Animal("Ai đó"); // Lỗi!

Cách khai báo phương thức trừu tượng

Phương thức trừu tượng là phương thức không có phần thân, tức là không có dấu ngoặc nhọn và mã bên trong. Nó được khai báo với từ khóa abstract và nhất định kết thúc bằng dấu chấm phẩy ;.

public abstract void makeSound();
  • Phương thức trừu tượng chỉ có thể được khai báo bên trong lớp trừu tượng.
  • Lớp kế thừa từ lớp trừu tượng bắt buộc phải triển khai tất cả các phương thức trừu tượng, nếu không chính nó cũng phải là abstract.

2. Kế thừa lớp trừu tượng: hoạt động thế nào

Hãy xem một ví dụ cụ thể. Giả sử có lớp trừu tượng Animal với phương thức trừu tượng makeSound(). Bây giờ tạo lớp con Dog triển khai phương thức này:

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // Gọi constructor của lớp cơ sở
    }

    @Override
    public void makeSound() {
        System.out.println(name + " sủa: Gâu gâu!");
    }
}

Và thêm một lớp kế thừa nữa:

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " kêu: Meo!");
    }
}

Bây giờ ta có thể sử dụng các lớp này trong chương trình:

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Sharik");
        Animal cat = new Cat("Murka");

        dog.makeSound(); // Sharik sủa: Gâu gâu!
        cat.makeSound(); // Murka kêu: Meo!

        dog.sleep(); // Sharik đang ngủ: Zzz...
        cat.sleep(); // Murka đang ngủ: Zzz...
    }
}

Lưu ý:
Ta có thể khai báo biến kiểu Animal, nhưng chỉ tạo được đối tượng của các lớp con cụ thể (không trừu tượng).

Sơ đồ: trông như thế nào


.         Animal (abstract)
            /         \
         Dog         Cat
 (cài đặt makeSound) (cài đặt makeSound)

3. Khi nào dùng lớp trừu tượng, khi nào dùng interface?

Đây là một trong những câu hỏi phổ biến nhất khi phỏng vấn — và có lý do! Hãy cùng phân tích:

  • Lớp trừu tượng — khi các đối tượng có trạng thái chung (ví dụ: trường), logic chung (phương thức đã triển khai), và bạn muốn đưa ra “bộ khung” hành vi với khả năng mở rộng.
  • Interface — khi bạn chỉ muốn xác định tập phương thức (hợp đồng), không có triển khai và không có trạng thái. Từ Java 8, interface có default/static-method, nhưng nhìn chung interface nói về “đối tượng cần làm gì”, không phải “làm như thế nào”.

Ví dụ đời thường:
“Chim” — là lớp trừu tượng: mọi con chim đều có mỏ, cánh, và có thể bay (nhưng theo những cách khác nhau).
“Biết bay” — là interface: không chỉ chim biết bay, mà còn máy bay và siêu anh hùng! Họ bay theo nhiều cách khác nhau, nhưng quan trọng là “biết bay”.

4. Ví dụ thực tiễn

Ví dụ 1: Lớp trừu tượng với triển khai một phần

Giả sử bạn làm một trò chơi có nhiều loại phương tiện khác nhau. Tất cả đều có thể di chuyển, nhưng theo những cách khác nhau. Tuy nhiên, tất cả đều có tốc độ, tên, và một cách dừng tiêu chuẩn.

public abstract class Transport {
    protected String name;
    protected int speed;

    public Transport(String name, int speed) {
        this.name = name;
        this.speed = speed;
    }

    // Phương thức trừu tượng — lớp con sẽ triển khai
    public abstract void move();

    // Phương thức đã triển khai
    public void stop() {
        System.out.println(name + " đã dừng lại.");
    }
}

public class Car extends Transport {
    public Car(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " chạy trên đường với tốc độ " + speed + " km/h.");
    }
}

public class Bicycle extends Transport {
    public Bicycle(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " đạp bàn đạp với tốc độ " + speed + " km/h.");
    }
}

Sử dụng:

Transport car = new Car("Toyota", 120);
Transport bike = new Bicycle("Stels", 25);

car.move(); // Toyota chạy trên đường với tốc độ 120 km/h.
bike.move(); // Stels đạp bàn đạp với tốc độ 25 km/h.

car.stop(); // Toyota đã dừng lại.
bike.stop(); // Stels đã dừng lại.

Ví dụ 2: Phương thức trừu tượng với tham số

public abstract class Shape {
    public abstract double area();
}

public class Circle extends Shape {
    private double radius;
    public Circle(double radius) {
        this.radius = radius;
    }
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends Shape {
    private double width, height;
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public double area() {
        return width * height;
    }
}

Sử dụng:

Shape c = new Circle(3);
Shape r = new Rectangle(4, 5);

System.out.println("Diện tích hình tròn: " + c.area());
System.out.println("Diện tích hình chữ nhật: " + r.area());

5. Đặc điểm và lưu ý của lớp trừu tượng

  • Lớp trừu tượng có thể dùng mọi mức truy cập: public, protected, private (ví dụ cho trường).
  • Có thể khai báo lớp trừu tượng mà không có phương thức trừu tượng. Hữu ích khi bạn chỉ muốn cấm tạo thể hiện của lớp cơ sở.
  • Nếu một lớp kế thừa lớp trừu tượng nhưng không triển khai tất cả phương thức trừu tượng, thì nó cũng phải được khai báo là abstract.
  • Lớp trừu tượng có thể có constructor. Chúng được gọi khi tạo đối tượng của lớp con (thông qua super(...)).
  • Phương thức trừu tượng không thể là private (nếu không sẽ không thể triển khai trong lớp con).
  • Lớp trừu tượng có thể chứa phương thức và trường static.
  • Lớp trừu tượng có thể triển khai các interface nhưng không bắt buộc phải triển khai các phương thức của chúng — lớp con có thể làm điều đó.

Bảng: so sánh lớp trừu tượng và interface

Lớp trừu tượng Interface
Từ khóa
abstract class
interface
Có thể chứa trường Có (bất kỳ) Từ Java 8 — chỉ static/final
Phương thức có triển khai Từ Java 8 — default/static
Phương thức trừu tượng
Kế thừa đa lần Không Có (có thể triển khai nhiều interface)
Constructor Không
Có thể tạo đối tượng Không Không

6. Các lỗi thường gặp khi làm việc với lớp và phương thức trừu tượng

Lỗi số 1: cố gắng tạo thể hiện của lớp trừu tượng.
Nếu bạn viết new Animal("Ai đó"), trình biên dịch sẽ nhắc ngay rằng lớp trừu tượng không dành cho việc này. Hãy nhớ: trừu tượng là “bộ khung”, không phải “cơ thể sống”.

Lỗi số 2: quên triển khai tất cả các phương thức trừu tượng trong lớp con.
Nếu lớp của bạn không triển khai ít nhất một phương thức trừu tượng của lớp cơ sở, thì bản thân nó phải được khai báo là abstract, nếu không sẽ gặp lỗi biên dịch.

Lỗi số 3: khai báo phương thức trừu tượng bên ngoài lớp trừu tượng.
Trong Java, không thể khai báo phương thức trừu tượng trong một lớp thông thường (không trừu tượng) — trình biên dịch sẽ báo lỗi ngay.

Lỗi số 4: cố gắng đặt phương thức trừu tượng là private hoặc static.
Phương thức trừu tượng không thể là private (nếu không sẽ không thể ghi đè) và không thể là static (vì phương thức tĩnh không thể ghi đè). Và cũng không thể là final, bởi final cấm ghi đè.

Lỗi số 5: quên bộ sửa đổi truy cập cho phương thức trừu tượng.
Nếu bạn không chỉ rõ, phương thức sẽ có phạm vi gói (package-private), đôi khi không đúng như mong muốn.

1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Một cư dân nữa của sở thú kỹ thuật số 🐾
Một cư dân nữa của sở thú kỹ thuật số 🐾
1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Hệ thống điều khiển "Nhà thông minh" 📱
Hệ thống điều khiển "Nhà thông minh" 📱
1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Trình chỉnh sửa hình học: các hình và diện tích của chúng 📐
Trình chỉnh sửa hình học: các hình và diện tích của chúng 📐
1
Nhiệm vụ
JAVA 25 SELF, mức độ, bài học
Đã khóa
Hệ thống nhân sự cho công ty CNTT 💼
Hệ thống nhân sự cho công ty CNTT 💼
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION