Trang chủHướng dẫnTop câu hỏi phỏng vấn OOP hay gặp nhất cho lập trình viên Java
Java

Top câu hỏi phỏng vấn OOP hay gặp nhất cho lập trình viên Java

CyStack blog 10 phút để đọc
CyStack blog07/10/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 10 minutes

Dù bạn đang làm việc với Java, C++, Python, hay bất kỳ ngôn ngữ lập trình hướng đối tượng nào khác, các khái niệm OOPS luôn là kim chỉ nam giúp bạn thiết kế và xây dựng các hệ thống mạnh mẽ, dễ bảo trì và mở rộng.

câu hỏi phỏng vấn OOP

Đó là lý do vì sao tôi quyết định tổng hợp và chia sẻ những câu hỏi phỏng vấn OOP thường gặp nhất, đi kèm lời giải thích chi tiết, giúp bạn không chỉ ghi nhớ mà còn thực sự hiểu sâu sắc từng khái niệm. Hãy cùng tôi khám phá cách OOPS giúp chúng ta mô hình hóa thế giới thực vào các chương trình phần mềm một cách hiệu quả.

1. OOPS là gì?

Hệ thống Lập trình Hướng Đối tượng (Object-Oriented Programming System – OOPS) là kỹ thuật lập trình được sử dụng để viết chương trình dựa trên các đối tượng trong thế giới thực. Trạng thái và hành vi của một đối tượng được biểu diễn thông qua các biến thành viên (member variables) và các phương thức. Trong lập trình OOPS, các chương trình được tổ chức xoay quanh đối tượng và dữ liệu thay vì chỉ tập trung vào hành động và logic.

2. Những ưu điểm chính của các khái niệm OOPS là gì?

Lập trình hướng đối tượng mang lại nhiều lợi ích đáng kể:

  • Đơn giản hóa (Simplicity): Các đối tượng trong OOPS mô hình hóa các thực thể trong thế giới thực, giúp chúng ta giảm thiểu độ phức tạp của chương trình và có một cấu trúc rõ ràng.
  • Tính Mô đun (Modularity): Mỗi đối tượng hình thành một thực thể riêng biệt, với các hoạt động bên trong được tách rời (decoupled) khỏi các phần khác của hệ thống. Điều này giúp chúng ta dễ dàng quản lý và phát triển các thành phần độc lập.
  • Khả năng Chỉnh sửa (Modifiability): Chúng ta dễ dàng thực hiện các thay đổi nhỏ trong cách biểu diễn dữ liệu hoặc các quy trình trong một chương trình hướng đối tượng. Các thay đổi bên trong một lớp không ảnh hưởng đến bất kỳ phần nào khác của chương trình, vì giao diện công khai (public interface) duy nhất mà thế giới bên ngoài tương tác với một lớp là thông qua việc sử dụng các phương thức của nó.
  • Khả năng Mở rộng (Extensibility): Khi chúng ta cần thêm các tính năng mới hoặc điều chỉnh để đáp ứng môi trường hoạt động thay đổi, chúng ta có thể giải quyết bằng cách thêm một vài đối tượng mới và sửa đổi một số đối tượng hiện có.
  • Khả năng Bảo trì (Maintainability): Chúng ta có thể bảo trì các đối tượng một cách riêng biệt, giúp việc định vị và sửa lỗi trở nên dễ dàng hơn rất nhiều.
  • Khả năng Tái sử dụng (Reusability): Chúng ta có thể tái sử dụng các đối tượng trong các chương trình khác nhau, tiết kiệm thời gian và công sức phát triển.

3. Sự khác biệt giữa lập trình thủ tục (Procedural programming) và OOPS là gì?

Chúng ta hãy xem xét sự khác biệt chính giữa hai mô hình lập trình này:

  • Lập trình thủ tục tập trung vào các hàm, trong khi lập trình hướng đối tượng dựa trên các đối tượng trong thế giới thực.
  • Lập trình thủ tục ưu tiên trình tự thực thi hàm, nhưng lập trình hướng đối tượng lại chú trọng vào các trạng thái và hành vi của đối tượng.
  • Lập trình thủ tục phơi bày dữ liệu ra toàn bộ chương trình, còn lập trình hướng đối tượng đóng gói dữ liệu bên trong các đối tượng.
  • Lập trình thủ tục tuân theo mô hình lập trình từ trên xuống (top-down), trong khi lập trình hướng đối tượng theo mô hình từ dưới lên (bottom-up).
  • Lập trình thủ tục có tính phức tạp hơn nên chúng ta khó sửa đổi, mở rộng và bảo trì; ngược lại, lập trình hướng đối tượng ít phức tạp hơn nên dễ dàng hơn trong việc sửa đổi, mở rộng và bảo trì.
  • Lập trình thủ tục cung cấp phạm vi tái sử dụng mã nguồn hạn chế, trong khi lập trình hướng đối tượng cung cấp phạm vi tái sử dụng mã nguồn rộng lớn hơn.

4. Các khái niệm cốt lõi của OOPS là gì?

Các khái niệm cốt lõi của OOPS bao gồm:

  • Abstraction (Trừu tượng hóa)
  • Encapsulation (Đóng gói)
  • Polymorphism (Đa hình)
  • Inheritance (Kế thừa)
  • Composition (Kết hợp)
  • Association (Liên kết)
  • Aggregation (Tập hợp)

5. Abstraction là gì?

Abstraction là một khái niệm trong OOPS giúp chúng ta xây dựng cấu trúc tổng thể của các đối tượng trong thế giới thực. Trong quá trình xây dựng này, chúng ta chỉ giữ lại các trạng thái và hành vi chung, và loại bỏ các trạng thái và hành vi cụ thể hơn, để dành cho người triển khai (implementers) định nghĩa sau.

6. Encapsulation là gì?

Encapsulation là một khái niệm trong OOPS giúp chúng ta tạo và định nghĩa các quyền hạn và giới hạn truy cập của một đối tượng cùng với các biến thành viên và phương thức của nó. Một ví dụ rất đơn giản để giải thích khái niệm này là chúng ta đặt các biến thành viên của một lớp ở chế độ private và cung cấp các phương thức public gettersetter để truy cập và sửa đổi chúng. Java cung cấp bốn loại bổ trợ mức truy cập (access level modifiers): public, protected, không có bổ trợ (package-private), và private.

7. Sự khác biệt giữa Abstraction và Encapsulation là gì?

Chúng ta có thể tóm tắt sự khác biệt giữa Abstraction và Encapsulation như sau:

  • “Lập trình theo giao diện, không theo triển khai” (Program to interfaces, not implementations) là nguyên tắc của Abstraction, còn “Đóng gói những gì thay đổi” (Encapsulate what varies) là nguyên tắc Hướng đối tượng của Encapsulation.
  • Trừu tượng hóa cung cấp một cấu trúc chung của một lớp và bỏ qua các chi tiết để người triển khai tự định nghĩa. Đóng gói giúp chúng ta tạo và định nghĩa các quyền truy cập và giới hạn của một đối tượng cùng với các biến thành viên và phương thức của nó.
  • Chúng ta triển khai Trừu tượng hóa trong Java bằng cách sử dụng interfaceabstract class, trong khi Đóng gói được triển khai bằng cách sử dụng bốn loại bổ trợ mức truy cập: public, protected, không có bổ trợ, và private.

8. Polymorphism là gì?

Polymorphism là khả năng một thứ tồn tại dưới nhiều hình thức khác nhau. Java hỗ trợ nhiều hình thức đa hình như biến tham chiếu đa hình (polymorphic reference variables), phương thức đa hình (polymorphic method), kiểu trả về đa hình (polymorphic return types), và kiểu đối số đa hình (polymorphic argument types).

9. Inheritance là gì?

Inheritance (Kế thừa) là khả năng một lớp con (subclass) có thể kế thừa các trạng thái và hành vi của lớp cha (super class) của nó.

10. Multiple Inheritance (Kế thừa đa cấp) là gì?

Một lớp con kế thừa trạng thái và hành vi từ nhiều lớp cha được gọi là kế thừa đa cấp.

// Ví dụ minh họa khái niệm Kế thừa Đa cấp (trong các ngôn ngữ hỗ trợ)
// (Lưu ý: Java không hỗ trợ kế thừa đa cấp cho lớp)
// class MyClass extends ParentA, ParentB {
//    // ...
// }

11. Vấn đề kim cương (Diamond Problem) trong kế thừa là gì?

Trong trường hợp kế thừa đa cấp, giả sử lớp A có hai lớp con là B và C, và một lớp D có hai lớp cha là B và C. Nếu một phương thức có trong A bị ghi đè bởi cả B và C nhưng không phải bởi D, thì D sẽ kế thừa phương thức đó từ lớp nào, B hay C? Vấn đề này được gọi là vấn đề kim cương.

// Sơ đồ vấn đề kim cương:
//      A
//     / \\\\
//    B   C
//     \\\\ /
//      D

// Nếu A có method()
// B override method()
// C override method()
// D không override method()
// Khi gọi D.method(), Java không biết nên gọi method() của B hay C.

12. Tại sao Java không hỗ trợ kế thừa đa cấp?

Java được thiết kế là một ngôn ngữ đơn giản và kế thừa đa cấp gây ra những phức tạp như vấn đề kim cương. Việc kế thừa trạng thái hoặc hành vi từ hai loại lớp khác nhau là một trường hợp thực tế rất hiếm gặp và chúng ta có thể dễ dàng đạt được điều đó thông qua mối quan hệ liên kết đối tượng (object association).

// Java giải quyết bằng interface: một lớp có thể implement nhiều interface
interface InterfaceA {
    void doSomething();
}

interface InterfaceB {
    void doSomething();
}

class MyClass implements InterfaceA, InterfaceB {
    // Chúng ta phải tự cung cấp triển khai cho doSomething()
    @Override
    public void doSomething() {
        System.out.println("Doing something from MyClass");
    }
}

13. Static Binding và Dynamic Binding là gì?

  • Static Binding (hoặc early binding) được giải quyết tại thời điểm biên dịch (compile time). Quá trình này xảy ra khi trình biên dịch có thể xác định chính xác phương thức nào sẽ được gọi dựa trên kiểu dữ liệu của biến tham chiếu. Nạp chồng phương thức (Method overloading) là một ví dụ của static binding.
class Calculator {
    // Static Binding: Nạp chồng phương thức
    public int add(int a, int b) {
        return a + b;
    }
    public double add(double a, double b) {
        return a + b;
    }
}
// Tại thời điểm biên dịch, Java biết sẽ gọi phiên bản add nào dựa trên kiểu đối số.

  • Dynamic Binding (hoặc late binding, hoặc virtual binding) được giải quyết tại thời điểm chạy (run time). Điều này xảy ra khi phương thức được gọi được xác định dựa trên kiểu dữ liệu thực tế của đối tượng chứ không phải kiểu của biến tham chiếu. Ghi đè phương thức (Method overriding) là một ví dụ của dynamic binding.
class Animal {
    // Dynamic Binding: Ghi đè phương thức
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof woof!");
    }
}

// Tại thời điểm chạy, JVM quyết định gọi makeSound() của Dog hay Animal.
// Animal myPet = new Dog();
// myPet.makeSound(); // Sẽ gọi makeSound() của Dog

14. Ý nghĩa của mối quan hệ “IS-A” và “HAS-A” là gì?

  • Mối quan hệ “IS-A” ngụ ý về sự kế thừa (Inheritance). Chúng ta nói một đối tượng lớp con có mối quan hệ “IS-A” với lớp cha hoặc interface. Ví dụ, nếu lớp A mở rộng (extends) lớp B, thì A “IS-A” B. Mối quan hệ này có tính bắc cầu (transitive), nghĩa là nếu lớp A mở rộng B và lớp B mở rộng C, thì A “IS-A” C. Chúng ta sử dụng toán tử instanceof trong Java để xác định mối quan hệ “IS-A”.
class Vehicle { /* ... */ }
class Car extends Vehicle { /* ... */ }

// Car IS-A Vehicle
// Car myCar = new Car();
// System.out.println(myCar instanceof Vehicle); // true

  • Mối quan hệ “HAS-A” xảy ra khi một lớp A có một biến tham chiếu thành viên thuộc kiểu B. Điều này còn được gọi là Tập hợp (Aggregation) hoặc Kết hợp (Composition).
class Engine { /* ... */ }
class Car {
    private Engine engine; // Car HAS-A Engine
    public Car(Engine engine) {
        this.engine = engine;
    }
}

15. Association là gì?

Association là một mối quan hệ giữa hai đối tượng, thường đi kèm với tính đa bội (multiplicity), mô tả số lượng đối tượng có thể liên quan với nhau. Nó biểu thị rằng các đối tượng có thể sử dụng lẫn nhau.

class Student {
    private String name;
    // Student có thể học nhiều Course
    // Course có thể có nhiều Student
}

class Course {
    private String title;
    // List<Student> students; // Ví dụ về Association
}

16. Aggregation là gì?

Aggregation còn được biết đến là mối quan hệ “HAS-A”. Khi lớp Car có một biến tham chiếu thành viên thuộc kiểu Wheel, thì mối quan hệ giữa các lớp CarWheel được gọi là Aggregation. Chúng ta có thể hiểu Aggregation là mối quan hệ “toàn thể và các bộ phận” (whole to its parts). Car là toàn thể và Wheel là một bộ phận. Tuy nhiên, Wheel có thể tồn tại mà không cần Car. Aggregation là một mối liên kết yếu.

class Wheel {
    private int size;
    // Wheel có thể tồn tại độc lập mà không cần Car
}

class Car {
    private String model;
    private Wheel frontLeftWheel; // Car HAS-A Wheel (Aggregation)
    private Wheel frontRightWheel;
    private Wheel rearLeftWheel;
    private Wheel rearRightWheel;

    public Car(Wheel fl, Wheel fr, Wheel rl, Wheel rr) {
        this.frontLeftWheel = fl;
        this.frontRightWheel = fr;
        this.rearLeftWheel = rl;
        this.rearRightWheel = rr;
    }
}

17. Composition là gì?

Composition là một dạng đặc biệt của Aggregation, trong đó bộ phận không thể tồn tại nếu thiếu toàn thể. Composition là một mối liên kết mạnh. Mối quan hệ Composition được biểu diễn tương tự như aggregation nhưng với một sự khác biệt là hình kim cương (trong sơ đồ UML) được tô đầy.

class Room {
    private String name;
    // Room không thể tồn tại độc lập nếu không có House
}

class House {
    private String address;
    private Room livingRoom; // House HAS-A Room (Composition) - Room không thể tồn tại nếu thiếu House
    private Room bedRoom;

    public House(String address) {
        this.address = address;
        this.livingRoom = new Room("Living Room"); // Room được tạo cùng với House
        this.bedRoom = new Room("Bedroom");
    }
}

18. Dependency là gì?

Khi một lớp phụ thuộc vào lớp khác vì nó sử dụng lớp đó tại một thời điểm nào đó, thì mối quan hệ này được gọi là Dependency. Một lớp phụ thuộc vào lớp khác nếu lớp độc lập là một biến tham số hoặc biến cục bộ của một phương thức của lớp phụ thuộc. Trong sơ đồ UML, một Dependency được vẽ bằng một đường nét đứt từ lớp phụ thuộc đến lớp độc lập với một mũi tên mở hướng về lớp độc lập.

class PaymentProcessor {
    public void processPayment(CreditCard card) { // PaymentProcessor depends on CreditCard
        // Logic xử lý thanh toán
        card.charge();
    }
}

class CreditCard {
    public void charge() {
        System.out.println("Charging card...");
    }
}
// PaymentProcessor phụ thuộc vào CreditCard vì nó sử dụng CreditCard làm tham số phương thức.

19. Sự khác biệt giữa Association và Dependency là gì?

Sự khác biệt chính giữa Association và Dependency nằm ở cách các lớp tương tác. Trong trường hợp Association, một lớp có một thuộc tính hoặc biến thành viên thuộc kiểu của lớp kia (mối quan hệ “HAS-A” lâu dài). Ngược lại, trong trường hợp Dependency, một phương thức của lớp này nhận một đối số thuộc kiểu của lớp kia hoặc một phương thức có một biến cục bộ thuộc kiểu của lớp kia (mối quan hệ tạm thời, chỉ tồn tại trong phạm vi của phương thức).

// Association (HAS-A):
class Order {
    private Customer customer; // Order HAS-A Customer (lâu dài)
    public Order(Customer customer) {
        this.customer = customer;
    }
}

class Customer { /* ... */ }

// Dependency:
class OrderService {
    public void createOrder(Customer customer, Product product) { // OrderService depends on Customer and Product (tạm thời)
        // Logic tạo order
        Order newOrder = new Order(customer);
        // ...
    }
}
class Product { /* ... */ }

20. Class là gì?

Class (Lớp) là một bản thiết kế (blueprint) hoặc khuôn mẫu (template) để tạo ra các đối tượng. Nó định nghĩa các đặc điểm (trạng thái) và hành vi mà các đối tượng được tạo ra từ nó sẽ có.

// Đây là một Class
class Dog {
    String name;     // Biến thành viên (state)
    String breed;

    public void bark() { // Phương thức (behavior)
        System.out.println(name + " barks!");
    }
}

21. Object là gì?

Object (Đối tượng) là một thể hiện (instance) cụ thể của một lớp. Khi chúng ta tạo một đối tượng từ một lớp, chúng ta đang tạo ra một thực thể cụ thể với các trạng thái và hành vi được định nghĩa trong lớp đó.

// Đây là một Object (thể hiện của lớp Dog)
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog(); // myDog là một Object
        myDog.name = "Buddy";
        myDog.breed = "Golden Retriever";
        myDog.bark(); // Buddy barks!
    }
}

Việc nắm vững OOPS giúp chúng ta thiết kế các hệ thống phức tạp bằng cách chia nhỏ chúng thành các thành phần dễ quản lý (đối tượng), thúc đẩy tái sử dụng mã (reusability), và cải thiện khả năng bảo trì (maintainability) theo thời gian. Đây là những kỹ năng không thể thiếu đối với bất kỳ nhà phát triển phần mềm nào muốn xây dựng các ứng dụng chất lượng cao.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất