1. Polymorphism là gì ?
Đa hình trong Java( Java Polymorphism) là một khái niệm mà chúng ta có thể thực hiện một hành động duy nhất theo nhiều cách khác nhau. Đa hình bắt nguồn từ 2 từ tiếng Hy Lạp: poly và morphs. Từ “poly” có nghĩa là nhiều và “morphs” có nghĩa là hình thức. Vì vậy, đa hình có nghĩa là nhiều hình thức.
Có hai loại đa hình trong Java là đa hình trong thời gian biên dịch (Compile-time polymorphism) và đa hình thời gian chạy (Runtime polymorphism). Chúng ta có thể thực hiện đa hình trong Java bằng cách nạp phương thức nạp chồng (Overloading Method) và phương thức ghi đè (Overriding Method).
2. Method Overloading (Phương thức nạp chồng)
Nếu một class có nhiều method có cùng tên nhưng khác tham số, thì được gọi là Method Overloading
Có 2 cách để tạo ra Method Overloading
- Thay đổi số lượng arguments
- Thay đổi kiểu dữ liệu
– Ví dụ:
public class SampleOverLoading { // Thay đổi số lượng arguments public int add(int a, int b) { return a + b; } public int add(int a, int b, int c) { return a + b + c; } // Thay đổi kiểu dữ liệu public float add(float a, float b) { return a + b; } public float add(float a, float b, float c) { return a + b + c; } }
3. Method overriding (Phương thức ghi đè)
Nếu Subclass có cùng method như được khai báo trong Superclass thì được gọi là method overriding trong Java.
Nói cách khác, nếu một lớp con cung cấp implements cụ thể của một method đã được định nghĩa trong Parent class thì được gọi là method overriding.
– Ví dụ 1:
// Nếu `Subclass` có cùng method như được khai báo trong `Superclass` thì được gọi là `method overriding` trong Java. // Super class public abstract class SampleAbstractClass { // abstract method public abstract void sayHello(); // abstract method has not body // no abstract method has body public int calculate(int a, int b) { return a + b; } // static method public static void sayGoodBye() { System.out.println("Bye!"); } // constructor protected SampleAbstractClass() { } // final method public final void noChangeBody(){ System.out.println("Lớp con không được thay đổi nội dung của phương thức này vì nó là final method"); } } // Subclass public class SampleExtendClass extends SampleAbstractClass { @Override // method overriding public void sayHello() { System.out.println("Hello, Tay Java"); } @Override // method overriding public int calculate(int a, int b) { return a * b; } }
– Ví dụ 2:
// Nói cách khác, nếu một lớp con cung cấp `implements` cụ thể của một method đã được định nghĩa trong `Parent class` thì được gọi là `method overriding`. // Subclass public interface SampleInterface { // constant fields String name = "Tây Java"; // abstract methods void method1(); int method2(); String methodN(); // default method default void sayHello() { System.out.println("Đây là sample interface"); } // static method static String getCurrentTime() { return String.valueOf(LocalDate.now()); } } // Parent class public class SampleMethodOverriding implements SampleInterface { @Override public void method1() { // code here } @Override public int method2() { return 0; } @Override public String methodN() { return ""; } @Override public void sayHello() { SampleInterface.super.sayHello(); // super key } }
4. Từ khoá quan trọng trọng super
, final
Từ khóa super
trong Java là một biến tham chiếu được sử dụng để tham chiếu đến đối tượng lớp cha trực tiếp. Khi sử dụng từ khóa super
ta có thể tham chiếu trực tiếp đến lớp cha và gọi các method hoặc constructor của Lớp cha.
Từ khóa final
được sử dụng trong java để hạn chế user, nó có thể áp dụng cho các ngữ cảnh với variable, method và class.
- Một variable được chỉ định với từ khóa final điều đó có nghĩa là variable này không thể thay đổi giá trị.
- Một method được chỉ định với từ khóa final điều đó có nghĩa là method này không thể overriding.
- Một class được chỉ định với từ khóa final điều đó có nghĩa là class này không thể được extends.
– Ví dụ:
// class này không thể được extends final class FinalClass { // code here } public class FinalMethod { // variable này không thể thay đổi giá trị final String keyword = "Final keyword"; // method này không thể overriding final void cannotChange() { } }
5. Câu hỏi phỏng vấn Java Polymorphism
1. Polymorphism là gì trong Java?
Polymorphism là một khái niệm trong lập trình hướng đối tượng cho phép các đối tượng có thể được xử lý theo nhiều hình thức khác nhau. Có hai loại đa hình trong Java:
- Compile-time polymorphism (Static polymorphism): Được thực hiện thông qua method overloading.
- Run-time polymorphism (Dynamic polymorphism): Được thực hiện thông qua method overriding.
2. Sự khác biệt giữa Overloading và Overriding là gì?
- Overloading (Nạp chồng phương thức): Cùng một tên phương thức nhưng khác tham số (số lượng, kiểu dữ liệu hoặc thứ tự). Nó xảy ra trong cùng một lớp và là ví dụ của compile-time polymorphism.
- Overriding (Ghi đè phương thức): Phương thức của lớp con có cùng tên, cùng tham số và kiểu trả về như phương thức của lớp cha. Đây là ví dụ của run-time polymorphism.
3. Giải thích về Compile-time polymorphism trong Java.
Compile-time polymorphism hay static polymorphism xảy ra khi quyết định gọi phương thức nào được thực hiện trong quá trình biên dịch. Đây là kết quả của phương thức overloading.
class Calculator { void add(int a, int b) { System.out.println(a + b); } void add(double a, double b) { System.out.println(a + b); } }
4. Giải thích về Run-time polymorphism trong Java.
Run-time polymorphism hay dynamic polymorphism xảy ra khi quyết định phương thức nào được gọi trong quá trình chạy của chương trình. Đây là kết quả của phương thức overriding và liên quan đến cơ chế late binding (ràng buộc muộn).
public class Animal { void sound() { System.out.println("Animal makes sound"); } } public class Dog extends Animal { void sound() { System.out.println("Dog barks"); } } Animal obj = new Dog(); obj.sound(); // Kết quả: "Dog barks"
5. Polymorphism có ý nghĩa gì trong việc sử dụng các lớp con của lớp cha?
Polymorphism cho phép một đối tượng của lớp con có thể được sử dụng như một đối tượng của lớp cha. Điều này giúp giảm sự phụ thuộc và tăng tính linh hoạt trong việc quản lý các đối tượng.
6. Tại sao cần sử dụng Polymorphism trong Java?
Polymorphism cung cấp tính linh hoạt và khả năng mở rộng của chương trình. Nó cho phép:
- Sử dụng chung các phương thức với tên gọi giống nhau nhưng thực hiện các hành vi khác nhau.
- Dễ dàng mở rộng và bảo trì mã nguồn bằng cách cho phép các lớp con triển khai lại các phương thức mà không thay đổi mã nguồn gốc.
7. Làm thế nào để Java quyết định phương thức nào sẽ được gọi khi sử dụng Polymorphism?
- Với overloading (nạp chồng), Java sẽ dựa vào số lượng, kiểu dữ liệu, và thứ tự tham số của phương thức được gọi trong thời gian biên dịch.
- Với overriding (ghi đè), Java sẽ dựa vào kiểu đối tượng thực sự trong thời gian chạy để xác định phương thức nào được gọi. Đây là kết quả của cơ chế dynamic binding.
8. Upcasting và Downcasting là gì?
Upcasting: Là quá trình chuyển đổi một đối tượng của lớp con thành kiểu của lớp cha. Điều này an toàn và được Java thực hiện tự động.
Animal animal = new Dog(); // Upcasting
9. Phương thức nào không thể overridden trong Java?
- Phương thức
final
: Không thể ghi đè (overridden). - Phương thức static: Không thể overridden, vì chúng thuộc về lớp, không thuộc về đối tượng.
- Phương thức private: Không thể overridden vì chúng không được kế thừa.
10. Constructor có thể được overridden không?
Không, constructor không thể bị overridden trong Java. Constructor chỉ được gọi một lần khi đối tượng được tạo và không thể kế thừa từ lớp cha.
11. Lợi ích của Polymorphism trong thiết kế phần mềm là gì?
- Tăng tính mở rộng: Bạn có thể thêm các lớp mới mà không thay đổi mã hiện có.
- Giảm sự phụ thuộc: Lớp cha không cần biết chính xác các lớp con sẽ cài đặt hành vi như thế nào.
- Dễ dàng bảo trì: Việc quản lý mã dễ dàng hơn do các lớp con có thể kế thừa và mở rộng chức năng mà không ảnh hưởng đến phần còn lại của chương trình.