Quay lại
Công Nghệ

Lập Trình Hướng Đối Tượng (OOP) trong Java

10 phút đọc3 thg 7, 2026
H

hoanggg2110

Tác giả

Lập Trình Hướng Đối Tượng (OOP) trong Java

Mở đầu

Nếu bạn đang học Java, sớm hay muộn bạn cũng sẽ gặp cụm từ OOP — Object-Oriented Programming (Lập trình hướng đối tượng). Đây không phải một tính năng thêm vào cho vui — OOP chính là cách Java được thiết kế từ đầu.

Thay vì viết code như một danh sách lệnh tuần tự (kiểu "làm cái này, rồi làm cái kia"), OOP cho phép bạn mô hình hóa chương trình theo các đối tượng trong thế giới thực. Một chiếc xe hơi, một tài khoản ngân hàng, một người dùng — tất cả đều có thể trở thành đối tượng trong code của bạn.

Bài viết này sẽ đưa bạn đi từ nền tảng (Class & Object) đến 4 trụ cột chính của OOP, kèm code Java minh họa cụ thể.


1. Nền Tảng: Class và Object

Trước khi nói về OOP, bạn cần nắm hai khái niệm cốt lõi.

Class — Bản thiết kế

Class là một bản thiết kế (blueprint) để tạo ra các đối tượng. Nó định nghĩa thuộc tính (dữ liệu) và hành vi (phương thức) mà đối tượng sẽ có.

Hãy nghĩ thế này: Car là một class (bản thiết kế xe hơi), còn chiếc BMW hay Mercedes ngoài đường là các object được tạo ra từ bản thiết kế đó.

public class Car {
    // Thuộc tính (fields)
    String color;
    String model;

    // Hành vi (methods)
    void drive() {
        System.out.println("Xe đang chạy.");
    }

    void stop() {
        System.out.println("Xe đã dừng.");
    }
}

Object — Thực thể cụ thể

Object là một thực thể cụ thể được tạo ra từ class. Trong Java, bạn tạo object bằng từ khóa new.

public class Main {
    public static void main(String[] args) {
        // Tạo object từ class Car
        Car myCar = new Car();
        myCar.color = "Đỏ";
        myCar.model = "Tesla Model S";

        myCar.drive(); // Output: Xe đang chạy.
        System.out.println("Model: " + myCar.model); // Output: Model: Tesla Model S
    }
}

Mỗi object có trạng thái (giá trị các thuộc tính), hành vi (các method có thể gọi), và định danh riêng trong bộ nhớ — ngay cả khi hai object có cùng dữ liệu, chúng vẫn là hai thực thể khác nhau.

Constructor — Khởi tạo đối tượng

Constructor là một phương thức đặc biệt được gọi tự động khi object được tạo ra. Nó dùng để khởi tạo giá trị ban đầu cho object.

public class Car {
    String color;
    String model;

    // Constructor
    public Car(String color, String model) {
        this.color = color;
        this.model = model;
    }
}

// Tạo object với constructor
Car myCar = new Car("Đỏ", "Tesla Model S");

Java hỗ trợ nhiều loại constructor: Default (không tham số), Parameterized (có tham số), Copy (sao chép từ object khác), và Private (ngăn tạo object từ bên ngoài).


2. Encapsulation — Đóng Gói Dữ Liệu

"Bảo vệ dữ liệu như két sắt — chỉ ai có chìa khóa mới truy cập được."

Encapsulation (Đóng gói) là nguyên tắc bao bọc dữ liệu và các phương thức thao tác dữ liệu vào trong một đơn vị duy nhất (class), đồng thời hạn chế truy cập trực tiếp từ bên ngoài.

Trong thực tế: Khi bạn dùng điều hòa, bạn chỉ nhấn nút tăng/giảm nhiệt độ — bạn không cần (và không được phép) chạm vào mạch điện bên trong.

Cách thực hiện trong Java

public class Student {
    private String name;  // Không ai truy cập trực tiếp được
    private int age;

    // Getter
    public String getName() {
        return name;
    }

    // Setter có validation
    public void setAge(int age) {
        if (age > 0) {  // Kiểm soát dữ liệu đầu vào
            this.age = age;
        }
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("Nguyễn Văn A");
        student.setAge(21);

        System.out.println("Tên: " + student.getName());
        System.out.println("Tuổi: " + student.getAge());
    }
}

Lợi ích của Encapsulation

Lợi ích Giải thích Bảo vệ dữ liệu Field private không bị thay đổi tùy tiện từ bên ngoài Kiểm soát truy cập Setter có thể validate dữ liệu trước khi gán Dễ bảo trì Thay đổi nội bộ không ảnh hưởng đến code bên ngoài Tăng tính linh hoạt Có thể thay đổi implementation mà không cần sửa toàn bộ hệ thống


3. Inheritance — Kế Thừa

"Đừng viết lại những gì đã có — hãy kế thừa và mở rộng."

Inheritance (Kế thừa) cho phép một class mới (subclass/lớp con) thừa hưởng các thuộc tính và phương thức của class có sẵn (superclass/lớp cha). Đây là cách Java thực hiện nguyên tắc "is-a" (là một loại).

Ví dụ: Dog là một Animal. Cat là một Animal. Thay vì viết lại hành vi ăn uống cho cả chó lẫn mèo, hãy để cả hai kế thừa từ Animal.

class Animal {
    void eat() {
        System.out.println("Con vật này đang ăn.");
    }
}

// Dog kế thừa Animal bằng từ khóa "extends"
class Dog extends Animal {
    void bark() {
        System.out.println("Gâu gâu!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();   // Kế thừa từ Animal — Output: Con vật này đang ăn.
        dog.bark();  // Phương thức riêng của Dog — Output: Gâu gâu!
    }
}

Các loại kế thừa trong Java

⚠️ Lưu ý quan trọng: Java không hỗ trợ multiple inheritance với class để tránh "Diamond Problem". Thay vào đó, hãy dùng Interface.


4. Polymorphism — Đa Hình

"Cùng một tên gọi, nhiều cách thể hiện khác nhau."

Polymorphism (Đa hình) — từ tiếng Hy Lạp có nghĩa là "nhiều hình dạng" — cho phép một phương thức hoặc đối tượng hoạt động khác nhau tùy theo ngữ cảnh.

Trong Java, Polymorphism có hai dạng chính:

4.1. Method Overloading — Đa hình tại Compile-time

Cùng một tên phương thức, nhưng khác nhau về số lượng hoặc kiểu tham số. Java tự động chọn phương thức phù hợp khi biên dịch.

class MathOperation {
    // Cộng 2 số nguyên
    int add(int a, int b) {
        return a + b;
    }

    // Cộng 3 số nguyên — cùng tên, khác tham số
    int add(int a, int b, int c) {
        return a + b + c;
    }

    // Cộng 2 số thực
    double add(double a, double b) {
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        MathOperation math = new MathOperation();
        System.out.println(math.add(5, 10));        // Output: 15
        System.out.println(math.add(5, 10, 15));    // Output: 30
        System.out.println(math.add(1.5, 2.5));     // Output: 4.0
    }
}

4.2. Method Overriding — Đa hình tại Runtime

Lớp con ghi đè phương thức của lớp cha để cung cấp cách thực thi riêng. Java quyết định dùng phương thức nào lúc chạy chương trình (runtime), dựa trên kiểu thực sự của object.

class Animal {
    void speak() {
        System.out.println("Con vật tạo ra âm thanh.");
    }
}

class Dog extends Animal {
    @Override
    void speak() {
        System.out.println("Chó sủa: Gâu gâu!");
    }
}

class Cat extends Animal {
    @Override
    void speak() {
        System.out.println("Mèo kêu: Meo meo!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();  // Kiểu khai báo: Animal, kiểu thực: Dog
        Animal animal2 = new Cat();

        animal1.speak(); // Output: Chó sủa: Gâu gâu!
        animal2.speak(); // Output: Mèo kêu: Meo meo!
    }
}

Chú ý: mặc dù biến animal1animal2 có kiểu Animal, Java vẫn gọi đúng phương thức của DogCat. Đây chính là sức mạnh của Runtime Polymorphism.


5. Abstraction — Trừu Tượng Hóa

"Hiển thị cái cần thiết — ẩn đi phần phức tạp."

Abstraction (Trừu tượng hóa) là kỹ thuật ẩn đi chi tiết triển khai, chỉ để lộ ra những gì người dùng cần biết.

Ví dụ thực tế: Khi bạn rút tiền ở ATM, bạn chỉ cần nhập số tiền và nhấn xác nhận — bạn không cần biết gì về các giao thức bảo mật, kết nối ngân hàng, hay cơ sở dữ liệu đằng sau.

Trong Java, Abstraction được thực hiện qua Abstract ClassInterface.

5.1. Abstract Class

Abstract class không thể tạo object trực tiếp. Nó định nghĩa các phương thức trừu tượng (không có body) mà các lớp con bắt buộc phải implement.

abstract class Shape {
    // Phương thức trừu tượng — không có body
    abstract void draw();

    // Phương thức bình thường — có thể có body
    void displayInfo() {
        System.out.println("Đây là một hình học.");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Vẽ hình tròn.");
    }
}

class Rectangle extends Shape {
    @Override
    void draw() {
        System.out.println("Vẽ hình chữ nhật.");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape shape1 = new Circle();
        Shape shape2 = new Rectangle();

        shape1.draw();       // Output: Vẽ hình tròn.
        shape1.displayInfo(); // Output: Đây là một hình học.
        shape2.draw();       // Output: Vẽ hình chữ nhật.
    }
}

5.2. Interface

Interface cung cấp khả năng trừu tượng hóa 100% (trước Java 8). Một class có thể implement nhiều interface, giải quyết hạn chế của multiple inheritance.

interface Drawable {
    void draw();
}

interface Resizable {
    void resize(int factor);
}

// Một class implement nhiều interface
class Circle implements Drawable, Resizable {
    @Override
    public void draw() {
        System.out.println("Vẽ hình tròn.");
    }

    @Override
    public void resize(int factor) {
        System.out.println("Phóng to hình tròn " + factor + " lần.");
    }
}

public class Main {
    public static void main(String[] args) {
        Circle c = new Circle();
        c.draw();      // Output: Vẽ hình tròn.
        c.resize(3);   // Output: Phóng to hình tròn 3 lần.
    }
}

Khi nào dùng Abstract Class, khi nào dùng Interface?

Abstract Class Interface Mức độ trừu tượng Một phần Hoàn toàn (trước Java 8) Kế thừa Chỉ extend một class Implement nhiều interface Constructor Có Không Dùng khi Các class có chung một "gốc" Định nghĩa hành vi chung cho nhiều loại class


6. Association — Mối Quan Hệ Giữa Các Object

Ngoài 4 trụ cột chính, OOP còn có khái niệm quan trọng là Association — cách các object liên kết và giao tiếp với nhau.

Aggregation (Liên kết yếu — "Has-A")

Một object chứa tham chiếu đến object khác, nhưng cả hai tồn tại độc lập.

Ví dụ: Một Company có nhiều Employee, nhưng khi công ty giải thể, các nhân viên vẫn tồn tại.

Composition (Liên kết mạnh — "Part-of")

Một object sở hữu object khác. Khi object cha bị hủy, object con cũng biến mất.

Ví dụ: Một House bao gồm các Room. Nhà bị phá, phòng không còn tồn tại độc lập.


Tổng Kết

OOP trong Java không chỉ là lý thuyết học thuật — đây là tư duy lập trình giúp bạn xây dựng phần mềm lớn, dễ bảo trì, và dễ mở rộng.

Trụ cột Mục đích Từ khóa chính Encapsulation Bảo vệ và kiểm soát dữ liệu private, getter/setter Inheritance Tái sử dụng code, mở rộng tính năng extends Polymorphism Linh hoạt, một tên nhiều cách dùng Overloading, Overriding Abstraction Ẩn phức tạp, chỉ lộ cần thiết abstract, interface

Nắm vững 4 khái niệm này, bạn đã có nền tảng vững chắc để tiến vào các chủ đề nâng cao hơn như Design Patterns, Spring Framework, hay kiến trúc Microservices.


Bạn đang học Java và gặp khó khăn ở phần nào? Để lại comment bên dưới — mình sẽ giải thích chi tiết hơn trong bài viết tiếp theo!


Thích bài viết này?

Nội dung trên Vết Mực luôn được chia sẻ miễn phí. Nếu bài viết mang lại giá trị cho bạn, hãy cân nhắc ủng hộ để chúng mình có thể duy trì máy chủ, phát triển thêm tính năng mới và tiếp tục xây dựng một không gian dành cho những người yêu viết lách. ✨

Các cách ủng hộ:

  • Viết và đăng bài trên Vết Mực
  • Chia sẻ bài viết với bạn bè
  • Góp ý để chúng mình cải thiện sản phẩm qua email: nsikhoa@gmail.com

Dù bạn chọn ủng hộ hay chỉ đơn giản là tiếp tục đọc và chia sẻ bài viết, đó đều là nguồn động lực rất lớn với chúng mình. ❤️

Bình luận

Đăng nhập để để lại bình luận.