oop-interview-questions

2026 年 52 個重要的 OOP 面試問題

你也可以在這裡找到全部 52 個答案 👉 Devinterview.io - OOP


1. 什麼是 物件導向程式設計 (Object-Oriented Programming, OOP)

物件導向程式設計是一種將程式碼組織為自我封裝物件的程式設計典範。

每個物件會結合資料與操作該資料的方法,讓程式碼更模組化、更彈性,也更可重用。

核心概念

類別與物件

類別 (class) 是建立物件的藍圖,定義其屬性與方法。

物件 (object) 是類別的實例。它同時包含資料 (類別的屬性) 與操作該資料的方法。

封裝

封裝 (Encapsulation) 是把資料與相關方法包在類別內,並將其隱藏以保護資料完整性。

外部程式通常透過公開方法存取它們,常見為 getter (讀取屬性) 與 setter (修改屬性)。

繼承

繼承 (Inheritance) 允許建立新類別並繼承既有類別的屬性與方法。它可促進程式碼重用,並建立階層關係。

被繼承的類別稱為基底類別 (base class)父類別 (superclass);進行繼承的類別稱為衍生類別 (derived class)子類別 (subclass)

多型

多型 (Polymorphism)衍生類別 (子類別) 的物件可被當成其基底類別 (父類別) 來使用,同時仍保有各自獨特行為。

這使得物件可對同一個方法呼叫做出不同反應,特別是在多個類別共享同名方法、但實作不同時。

抽象化

抽象化 (Abstraction) 重點在於建立簡潔介面,只暴露相關且必要的功能。

關聯

物件常會與其他物件建立關係,例如一個物件使用或包含另一個物件;這類關係稱為關聯 (associations)

OOP 的好處

程式碼範例:OOP

以下是 Java 程式碼:

// Abstract base class
abstract class Animal {
    private String name;

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

    public String getName() {
        return name;
    }

    // Abstract method
    public abstract void makeSound();

    public void sleep() {
        System.out.println(name + " is sleeping.");
    }
}

// Derived class
class Lion extends Animal {
    public Lion(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println("Roar!");
    }
}

// Derived class
class Parrot extends Animal {
    private String color;

    public Parrot(String name, String color) {
        super(name);
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    @Override
    public void makeSound() {
        System.out.println("Squawk!");
    }
}

public class Zoo {
    public static void main(String[] args) {
        Lion simba = new Lion("Simba");
        Parrot rio = new Parrot("Rio", "Blue");

        System.out.println(simba.getName() + " is a Lion.");
        simba.makeSound();
        simba.sleep();

        System.out.println(rio.getName() + " is a " + rio.getColor() + " Parrot.");
        rio.makeSound();
        rio.sleep();
    }
}

在這個範例中:

2. 程序式物件導向 程式設計有什麼差異?

程序式 (Procedural)物件導向程式設計 (OOP) 是不同的程式設計典範。程序式偏向線性、以任務為中心;OOP 則強調以物件封裝資料與行為。

主要差異

資料與函式管理

程式碼抽象化與可重用性

繼承與多型

不同語言中的 OOP 與程序式

實務上,像 Python、JavaScript、C# 等現代語言多半支援多種典範,可依任務需求彈性選擇。

程式碼範例:程序式做法

以下是 Python 程式碼:

class Animal:
    def __init__(self, sound):
        self.sound = sound

def make_sound(animal):
    print(animal.sound)

dog = Animal("Woof")
cat = Animal("Meow")

make_sound(dog)
make_sound(cat)

程式碼範例:物件導向做法

以下是 Java 程式碼:

import java.util.ArrayList;
import java.util.List;

abstract class Animal {
    public abstract void makeSound();
}

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

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

public class Main {
    public static void main(String[] args) {
        List<Animal> animals = new ArrayList<>();
        animals.add(new Dog());
        animals.add(new Cat());

        for (Animal animal : animals) {
            animal.makeSound();
        }
    }
}


3. 什麼是 封裝 (encapsulation)

封裝是物件導向程式設計原則之一,指的是把資料與操作該資料的方法整合在同一個單位,也就是物件

核心概念

封裝的好處

實務應用

程式碼範例:封裝

以下是 Java 程式碼:

public class Car {
    private int fuel;  // private ensures that fuel can't be accessed directly from outside the class

    public Car() {
        this.fuel = 100;  // Initialize with 100 units of fuel
    }

    // Getter method for fuel
    public int getFuel() {
        return fuel;
    }

    // Setter method for fuel with encapsulation enforcing constraints
    public void setFuel(int fuel) {
        if (fuel >= 0 && fuel <= 100) {
            this.fuel = fuel;
        } else {
            System.out.println("Invalid fuel amount.");
        }
    }

    public void drive() {
        if (fuel > 0) {
            fuel--;
            System.out.println("Vroom!");
        } else {
            System.out.println("Out of fuel!");
        }
    }

    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.drive();
        System.out.println("Fuel remaining: " + myCar.getFuel());
        myCar.setFuel(120);  // This will print "Invalid fuel amount."
    }
}


4. 什麼是 多型 (polymorphism)?請解釋 覆寫 (overriding)多載 (overloading)

在物件導向程式設計中,多型可讓不同型別的物件透過共同介面被一致地使用。它能抽象化方法細節,提升程式碼彈性與可重用性。

核心概念

多載 (編譯期多型)

同一個類別中的多個方法可使用相同名稱,但參數不同,因而可以共存。編譯器會依方法簽章選擇對應方法。

程式碼範例:多載

以下是 Java 程式碼:

public class Sum {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }
}

覆寫 (執行期多型)

子類別會對父類別已定義的方法提供特定實作,等同取代父類別版本。實際呼叫哪個方法,會在程式執行時決定。

程式碼範例:覆寫

以下是 Python 程式碼:

class Animal:
    def speak(self):
        return "Animal speaks"

class Cat(Animal):
    def speak(self):
        return "Cat meows"

obj_cat = Cat()
print(obj_cat.speak())  # Output: Cat meows

虛擬方法 (如 C++)

在基底類別中以 virtual 標記的方法,可在衍生類別覆寫。這可啟用動態派發 (dynamic dispatch),即使透過基底類別參考,也能呼叫正確方法。

程式碼範例:虛擬方法

以下是 C++ 程式碼:

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void speak() {
        cout << "Animal speaks";
    }
};

class Cat : public Animal {
public:
    void speak() override {
        cout << "Cat meows";
    }
};

動態派發與延遲繫結

多型常透過動態派發機制,在執行期決定要呼叫哪個具體方法。

這也稱為延遲繫結 (late binding)。此特性可讓通用程式碼處理多種物件型別,提升彈性與適應性。

5. 什麼是 繼承 (inheritance)?請說明一些 繼承類型

繼承是物件導向程式設計中的核心概念,讓你能基於既有類別建立新類別

繼承建立的是 **「is-a」關係 **:衍生類別 (也叫子類別) 會繼承父類別 (基底類別) 的屬性與行為。

繼承的類型

  1. 單一繼承 (Single Inheritance):一個類別只繼承一個基底類別。Java 中很常見。

    例:類別 B 繼承類別 A

  2. 多重繼承 (Multiple Inheritance):一個類別繼承多個基底類別。C++ 支援;Java 常用介面達成類似效果,以避免「菱形問題」等複雜性。

    例:類別 C 同時繼承 AB

  3. 多層繼承 (Multilevel Inheritance):一個類別繼承另一個衍生類別。

    例:類別 C 繼承 B,而 B 繼承 A

  4. 階層式繼承 (Hierarchical Inheritance):同一個基底類別被多個子類別繼承。

    例:類別 BC 都繼承 A

  5. 混合繼承 (Hybrid Inheritance):上述兩種以上繼承型態的組合,使用上可能帶來複雜度。

    例:在 C++ 中,一個類別可同時涉及多重繼承與多層繼承。

程式碼範例:不同繼承類型

以下是 Java 程式碼:

// Single Inheritance
class A {
    void funcA() {
        System.out.println("Function of class A");
    }
}

class B extends A { }  // Class B inherits from class A


// Multiple Inheritance using interfaces
interface X {
    void funcX();
}

interface Y {
    void funcY();
}

class Z implements X, Y {  // Class Z implements both interface X and interface Y
    public void funcX() {
        System.out.println("Function of interface X");
    }

    public void funcY() {
        System.out.println("Function of interface Y");
    }
}


// Multilevel Inheritance
class A {
    void funcA() {
        System.out.println("Function of class A");
    }
}

class B extends A {
    void funcB() {
        System.out.println("Function of class B");
    }
}

class C extends B { }  // Class C inherits from class B, which inherits from class A


// Hierarchical Inheritance
class H {
    void funcH() {
        System.out.println("Function of class H");
    }
}

class I extends H { }  // Class I inherits from class H

class J extends H { }  // Class J also inherits from class H


// Java does not directly support hybrid inheritance through classes.
// However, you can achieve something similar using interfaces, as shown with multiple inheritance.


6. 什麼是 抽象化 (abstraction)?請說明一些 抽象化技巧

在物件導向程式設計 (OOP) 中,抽象化是聚焦於關鍵特徵、隱藏不必要細節的概念。

它能清楚區分高層概念與具體實作,進而提升可重用性可維護性安全性

抽象化技巧

抽象類別

介面

程式碼範例:抽象化技巧

以下是 Java 程式碼:

// Abstract Class
abstract class Vehicle {
    // Abstract method (no body)
    public abstract String start();

    // Regular method
    public String stop() {
        return "Vehicle stopped!";
    }
}

// Implementing the abstract class
class Car extends Vehicle {
    @Override
    public String start() {
        return "Car started!";
    }
}

// Interface
interface Drivable {
    // All methods in an interface are implicitly abstract
    void drive();
}

// Implementing both the abstract class and the interface
class Bike extends Vehicle implements Drivable {
    @Override
    public String start() {
        return "Bike started!";
    }

    @Override
    public void drive() {
        System.out.println("Bike is being driven!");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        System.out.println(car.start()); // Output: Car started!
        System.out.println(car.stop());  // Output: Vehicle stopped!

        Bike bike = new Bike();
        System.out.println(bike.start()); // Output: Bike started!
        bike.drive();                     // Output: Bike is being driven!
    }
}


7. 在 OOP 中,什麼是 類別 (class)

在物件導向程式設計中,類別是建立物件 (實例) 的藍圖。它在同一個結構下封裝屬性 (資料) 與行為 (方法)。

建立實例後,每個物件都可攜帶各自資料,同時遵循其類別藍圖。

類別的關鍵組成

類別中的 OOP 原則

程式碼範例:Car 類別

以下是 Python 程式碼:

class Car:
    """A class to represent a car."""

    def __init__(self, make, model, year):
        """Initialize car attributes."""
        self.make = make
        self.model = model
        self.year = year
        self.fuel = 0

    def fill_tank(self, gallons):
        """Add fuel to the tank. Ensure the amount is positive."""
        if gallons > 0:
            self.fuel += gallons
        else:
            print("Invalid fuel amount.")

    def drive(self, distance=1):
        """Drive the car, consuming fuel based on distance."""
        if self.fuel >= distance:
            self.fuel -= distance
            print(f"Car drove {distance} unit(s). Remaining fuel: {self.fuel} units.")
        else:
            print("Insufficient fuel.")

# Create a Car object
my_car = Car("Honda", "Civic", 2022)

# Access its attributes and methods
my_car.fill_tank(10)

for _ in range(15):
    my_car.drive()


8. 在 OOP 中,什麼是 物件 (object)

物件類別的具體實例。它在單一單位中封裝資料 (屬性) 與行為 (方法)。

核心特性

物件生命週期

  1. 建立 (Creation):物件由類別透過「實例化 (instantiation)」建立。
  2. 操作 (Manipulation):可透過屬性修改與方法呼叫改變狀態。
  3. 銷毀 (Destruction):終止物件存在,通常由語言自動處理 (如垃圾回收),或透過程式碼明確處理。

程式碼範例:物件實例化

以下是 Python 程式碼:

class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def bark(self):
        print("Woof!")

myDog = Dog("Buddy", "Golden Retriever")


9. 存取修飾詞 (access specifiers) 如何運作?常見有哪些?

在物件導向程式設計 (OOP) 中,存取修飾詞用來定義類別成員的可見性與可存取範圍。

存取修飾詞類型

  1. Private:成員僅能在定義它的類別內存取,確保資料封裝。
  2. Protected:成員可在定義類別及其子類別中存取。
  3. Public:成員可被所有類別全域存取。

程式碼範例:存取修飾詞

以下是 Java 程式碼:

public class Car {
    private String make;  // Accessible only within class
    protected int year;   // Accessible within class and subclasses
    double price;         // Default visibility: package-private

    public void setMake(String make) {
        this.make = make;
    }

    public String getMake() {
        return make;
    }

    protected void startEngine() {
       System.out.println("Engine started!");
    }
}

核心概念

常見錯誤

最佳實務

10. 請列出幾種 方法多載 (overload) 的方式。

以下介紹三種常見的方法多載技巧。

1. 改變參數數量

此方式是透過改變方法簽章中的參數數量。

以下是 Java 範例:

public int calculateSum(int a, int b) { // Two parameters
    return a + b;
}

public int calculateSum(int a, int b, int c) { // Three parameters
    return a + b + c;
}

2. 調整參數順序

另一種方式是重排方法中的參數順序,形成不同簽章。

以下是 Java 範例:

public double calculateArea(double length, double width) { // Length, then width
    return length * width;
}

public double calculateArea(double radius) { // Just radius for a circle
    return Math.PI * radius * radius;
}

3. 變更參數型別

你也可以透過定義不同參數型別的方法達成多載

以下是 Java 範例:

public void printDetails(String name, int age) {
    System.out.println("Name: " + name + " , Age: " + age);
}

public void printDetails(int id) {
    System.out.println("ID: " + id);
}

public void printDetails(double salary) {
    System.out.println("Salary: " + salary);
}


11. 在 OOP 中,什麼是 高內聚 (cohesion)

OOP 中的內聚 (Cohesion) 指的是同一類別內的方法與資料彼此關聯的緊密程度。高內聚類別會聚焦於特定任務或職責,因此更容易維護、理解與確保可靠性。

高內聚是理想特性,代表類別中的方法與屬性能以一致方式協作;相對地,低內聚表示類別包含多個且常互不相關的責任,會增加理解與維護難度。

內聚等級

  1. 偶然內聚 (Coincidental):類別內的方法與屬性幾乎沒有實質關聯。
  2. 邏輯內聚 (Logical):方法因某種邏輯被歸在一起,但缺乏明確主題。
  3. 時間內聚 (Temporal):方法因執行時機相同而相關,例如初始化方法。
  4. 程序內聚 (Procedural):方法依固定流程順序執行。
  5. 通訊內聚 (Communicational):方法操作同一組資料。
  6. 序列內聚 (Sequential):一個方法輸出成為另一方法輸入。
  7. 功能內聚 (Functional):類別中所有方法都服務於單一明確任務。

其中,功能內聚最理想,因為它與單一職責原則 (Single Responsibility Principle) 最一致。

程式碼範例:低內聚層級

以下是 Java 程式碼:

public class FileUtility {

    public String readFile(String fileName) {
        // Read a file
        return content;
    }

    public void writeToDatabase(String data) {
        // Write content to a database
    }

    public void clearCache() {
        // Clear application cache
    }

    public List<String> parseFile(String content) {
        // Parse file content
        return parsedData;
    }
}

這個 FileUtility 類別屬於低內聚,因為它混合了檔案操作、資料庫寫入與快取管理。

改善內聚的建議

  1. 單一職責原則 (SRP):每個類別應只有一個變動原因,也就是只專注於一項任務或責任。
  2. 封裝:鼓勵資料隱藏,只透過聚焦且相關的方法對外暴露資料。

12. 在 OOP 中,什麼是 耦合 (coupling)

OOP 中的耦合 (Coupling) 描述類別或模組間的相依程度。它決定不同模組或類別彼此連結的緊密程度,並影響系統彈性、可維護性與可測試性。

在軟體設計中通常偏好低耦合 (loose coupling)

耦合類型

  1. 內容耦合 (Content Coupling):最強耦合型態,一個模組直接存取或修改另一模組內部資料。

  2. 共用耦合 (Common Coupling):多個模組共享全域資料;共享資源的任何改動都可能影響所有相依模組。

  3. 控制耦合 (Control Coupling):一個模組透過控制資訊 (如旗標) 影響另一模組流程。

  4. 外部耦合 (External Coupling):類別或模組因外部因素連結,例如設定檔或資料結構 (schema)。

  5. 印記 (資料) 耦合 (Stamp/Data Coupling):模組共享資料結構但僅用其中一部分,需了解傳遞資料的結構細節。

  6. 訊息耦合 (Message Coupling):最低耦合型態,模組僅透過標準介面 (如方法呼叫或訊息) 溝通。

與 SOLID 原則的關係

13. 什麼是 建構子 (constructor)?如何使用?

建構子物件導向程式設計中的特殊方法,用於初始化物件。它可確保新建立的物件具備合適初始狀態與必要資源。

核心概念

目的

特性

建構子類型

  1. 預設建構子 (Default Constructors)
    • 不帶參數。
    • 若未定義任何建構子,語言通常會自動提供。
  2. 參數化建構子 (Parameterized Constructors)
    • 可接收參數以進行自訂初始化。
    • 常用於提供屬性或欄位初始值。
  3. 複製建構子 (Copy Constructors)
    • 接收同型別的另一個物件,並以其值初始化目前物件。
    • 在 C++ 等語言中常用於深拷貝。
  4. 靜態建構子 (Static Constructors)
    • 用於初始化靜態成員或其他類別層級動作。
    • 不參與物件建立,且在許多 OOP 語言中可能不存在。

程式碼範例:建構子

以下是 Java 程式碼:

class Vehicle {
    private String vehicleType;
    private int wheels;

    // Default Constructor
    public Vehicle() {
        vehicleType = "Car";
        wheels = 4;
    }

    // Parameterized Constructor
    public Vehicle(String type, int wheelCount) {
        vehicleType = type;
        wheels = wheelCount;
    }

    public void showDetails() {
        System.out.println("Type of Vehicle: " + vehicleType);
        System.out.println("Number of Wheels: " + wheels);
    }

    public static void main(String[] args) {
        // Calling Default Constructor
        Vehicle car = new Vehicle();
        car.showDetails();

        // Calling Parameterized Constructor
        Vehicle bike = new Vehicle("Bike", 2);
        bike.showDetails();
    }
}

以下是 C++ 程式碼:

#include <iostream>
using namespace std;

class Person {
    private:
        string name;
        int age;

    public:
        // Parameterized Constructor
        Person(string n, int a) {
            name = n;
            age = a;
        }

        void displayInfo() {
            cout << "Name: " << name << ", Age: " << age << endl;
        }
};

int main() {
    // Calling Parameterized Constructor
    Person p1 = Person("Alice", 25);
    p1.displayInfo();

    return 0;
}

以下是 C# 程式碼:

using System;

class Car {
    private string model;

    // Parameterized Constructor
    public Car(string m) {
        model = m;
    }

    static void Main() {
        // Calling Parameterized Constructor
        Car c = new Car("Toyota");
        Console.WriteLine("Car Model: " + c.model);
    }
}


14. 請描述 OOP 中的 解構子 (destructor)終結器 (finalizer) 概念。

物件導向程式設計中,解構子 (或類別的終結器) 用於在物件被銷毀前執行清理動作。

物件銷毀

物件可透過明確隱含方式被銷毀:

解構子

解構子是特殊方法,會在物件即將離開作用域或被明確銷毀前自動呼叫。其主要目的在釋放資源或執行清理工作,例如關閉檔案、釋放記憶體。

使用情境

垃圾回收

在記憶體管理上,垃圾回收是專門負責自動回收記憶體的機制。在 Java、C# 等語言中,因垃圾回收可靠,通常不一定需要解構子。

給 Java 開發者的提醒

Java 曾提供 finalize() 方法,概念類似解構子。如今通常不建議使用,改以 AutoCloseable 介面與 try-with-resources 來更妥善管理資源。

程式碼範例:C++

以下是 C++ 程式碼:

class Resource {
public:
    Resource() { std::cout << "Resource Acquired\n"; }
    ~Resource() { std::cout << "Resource Destroyed\n"; }
};

int main() {
    Resource r;
}  // Destructs r here

非記憶體資源

除記憶體外,解構子也可管理多種資源,例如:

程式碼範例:資源管理

以下是 C++ 程式碼:

#include <iostream>
#include <fstream>

class FileHandler {
public:
    std::ofstream file;
    FileHandler(std::string fileName) {
        file.open(fileName);
        if (file.is_open()) {
            std::cout << "File Opened\n";
        }
    }
    ~FileHandler() {
        if (file.is_open()) {
            file.close();
            std::cout << "File Closed\n";
        }
    }
};

int main() {
    FileHandler fh("sample.txt");
}  // Destructor called on fh, closes the file


15. 比較 繼承 vs. Mixin vs. 組合 (composition)

繼承mixin組合 (composition) 都是物件導向程式設計中與程式碼重用、物件/類別關係相關的技術。

以下分別說明並比較:

繼承

Mixin

組合

許多現代 OOP 設計準則 (例如 composition over inheritance) 都建議:除非有明確「is-a」關係,通常優先使用組合,因為更有彈性,也更容易維護。

在這裡探索全部 52 個答案 👉 Devinterview.io - OOP