Method Overriding (parent ရဲ့ method ကို child က အစားထိုး ရေးခြင်း)
B3.2 (HL): Override methods in subclasses to provide specialised behaviour.
မြန်မာလို: subclass (အမွေဆက်ခံတဲ့ child class) တွေမှာ သီးသန့် behaviour (object က လုပ်နိုင်တာတွေ) ပေးဖို့ method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း) တွေကို override (parent ရဲ့ method ကို child က အစားထိုး ရေး) လုပ်နိုင်ရပါမယ်။
ဒီစာမျက်နှာက အကြောင်းအရာတွေကို HL အဆင့်မှာပဲ စစ်ဆေးပါတယ်။ SL (Standard Level) နဲ့ HL (Higher Level) ဆိုတာ IB Computer Science (နိုင်ငံတကာ ကျောင်းတွေမှာ သင်တဲ့ ကွန်ပျူတာသိပ္ပံ သင်ရိုး) သင်တန်းရဲ့ အဆင့်နှစ်ဆင့်ဖြစ်ပြီး HL အပိုင်းတွေက ပိုနက်နက်ရှိုင်းရှိုင်း လေ့လာရတဲ့ အပိုင်းတွေပါ။
အဓိက အယူအဆများ
Method Overriding ဆိုတာ ဘာလဲ
Child class တစ်ခုက သူ့ parent class ထဲက method တစ်ခုနဲ့ နာမည်တူ၊ parameter (method ကို ပေးလိုက်တဲ့ တန်ဖိုးကို လက်ခံတဲ့ variable) တူ၊ return type (method က ပြန်ပေးတဲ့ ဒေတာ အမျိုးအစား) တူတဲ့ method ကို ရေးလိုက်ရင် child type ဖြစ်တဲ့ object (class တစ်ခုကနေ ဖန်တီးထားတဲ့ instance) တွေအတွက် child ရဲ့ version က parent ရဲ့ version ကို အစားထိုးပါတယ်။ ဒါကို method overriding လို့ ခေါ်ပါတယ်။
public class Animal {
public String speak() {
return "...";
}
}
public class Dog extends Animal {
@Override
public String speak() {
return "Woof!";
}
}
public class Cat extends Animal {
@Override
public String speak() {
return "Meow!";
}
}
class Animal():
def speak(self):
return "..."
class Dog(Animal):
def speak(self): # same name, same parameters - this IS the override
return "Woof!" # (Python has no @Override annotation)
class Cat(Animal):
def speak(self):
return "Meow!"
Dog d = new Dog();
Cat c = new Cat();
Animal a = new Animal();
System.out.println(d.speak()); // Woof!
System.out.println(c.speak()); // Meow!
System.out.println(a.speak()); // ...
d = Dog()
c = Cat()
a = Animal()
print(d.speak()) # Woof!
print(c.speak()) # Meow!
print(a.speak()) # ...
Subclass တစ်ခုစီက speak() ရဲ့ ကိုယ်ပိုင် version ကို ပေးပါတယ်။ Dog ပေါ်မှာ speak() ကို ခေါ်ရင် Java က Animal ရဲ့ version ကို မဟုတ်ဘဲ Dog ရဲ့ version ကို သုံးပါတယ်။
The @Override Annotation (override လုပ်ကြောင်း compiler ကို ပြောတဲ့ အမှတ်အသား)
@Override ဆိုတာ compiler (code တစ်ခုလုံးကို ကြိုတင် ဘာသာပြန်တဲ့ program) ကို “parent method တစ်ခုကို override လုပ်ဖို့ ရည်ရွယ်ပါတယ်” လို့ ပြောဖို့ method ရဲ့ အပေါ်မှာ ရေးတဲ့ annotation (code အကြောင်း compiler ကို အချက်ပြတဲ့ အမှတ်အသား) ပါ။ မထည့်လည်း ရပေမယ့် ထည့်ဖို့ အထူး အကြံပြုပါတယ်၊ ဘာလို့လဲဆိုတော့:
- Method နာမည်ကို စာလုံးပေါင်း မှားရင် compiler က ချက်ချင်း ဖမ်းမိပါတယ်
- Parameter type တွေကို မတော်တဆ ပြောင်းမိရင် compiler က သတိပေးပါတယ်
- Code ကို ဖတ်ရ ပိုလွယ်စေပါတယ်: class ကို ဖတ်တဲ့ ဘယ်သူမဆို ဒီ method က parent ရဲ့ version ကို အစားထိုးတယ်ဆိုတာ သိပါတယ်
@Override
public String speak() { // compiler checks: does Animal have speak()?
return "Woof!";
}
def speak(self): # Python has no @Override - redefining the method is the override
return "Woof!"
# Watch out: a typo like speek() silently creates a NEW method - Python gives no warning
Java code ထဲက မှတ်ချက်က compiler က Animal မှာ speak() ရှိလား စစ်တယ်လို့ ဆိုလိုပါတယ်။ Python code ထဲက မှတ်ချက်တွေကတော့ Python မှာ @Override မရှိလို့ method ကို ပြန်ရေးလိုက်တာနဲ့ override ဖြစ်ကြောင်း၊ speek() လို စာလုံးပေါင်း အမှားက ဘာသတိပေးချက်မှ မပြဘဲ method အသစ် တစ်ခုကို ဖန်တီးလိုက်ကြောင်း သတိပေးပါတယ်။
@Override မပါရင် speek() လို စာလုံးပေါင်း အမှားက parent ရဲ့ speak() ကို override လုပ်မယ့်အစား method အသစ် တစ်ခုကို ဖန်တီးလိုက်ပါလိမ့်မယ်။ Code က compile ဖြစ်ပေမယ့် မှားမှား အလုပ်လုပ်ပါလိမ့်မယ်: သတိထားမိခက်တဲ့ bug (code ထဲက အမှား) တစ်ခုပါ။ (Python မှာ ဒီထောင်ချောက်က ပိုဆိုးပါတယ်: စာလုံးပေါင်း အမှားကို ဖမ်းပေးမယ့် annotation မရှိလို့ စာလုံးပေါင်းကို သေချာ စစ်ပါ။)
Method ကို override လုပ်တဲ့အခါ
@Overrideကို အမြဲ သုံးပါ။ ဒါဆိုရင် compiler က အဲဒီ method က parent class ထဲက method တစ်ခုကို တကယ် override လုပ်လား စစ်ပေးလို့ နာမည် စာလုံးပေါင်း မှားတာ ဒါမှမဟုတ် parameter list မှားတာကို program မ run ခင်မှာပဲ ဖမ်းမိပါတယ်။
Override လုပ်ရာမှာ လိုက်နာရမယ့် စည်းမျဉ်းများ
Method တစ်ခုက parent method ကို override လုပ်ဖို့ ဒါတွေ ရှိရပါမယ်:
- Parent နဲ့ method နာမည် တူရမယ်
- Parameter list တူရမယ် (အရေအတွက်၊ type နဲ့ အစဉ်)
- Return type တူရမယ် (ဒါမှမဟုတ် subtype ဖြစ်ရမယ်၊ subtype ဆိုတာ အဲဒီ type ကနေ အမွေဆက်ခံထားတဲ့ type ပါ)
- Access modifier (ဘယ်ကနေ သုံးခွင့်ရလဲ သတ်မှတ်တဲ့ keyword) က တူရမယ်၊ ဒါမှမဟုတ် ကန့်သတ်မှု ပိုနည်းရမယ် (ဥပမာ
protectedparent method ကိုpublicအဖြစ် override လုပ်လို့ ရပေမယ့်privateအဖြစ်တော့ မရပါဘူး)
ဒီထဲက တစ်ခုခု မတူရင် override မဟုတ်ပါဘူး: method အသစ် တစ်ခုပါ။ အဲဒါက overloading (နာမည်တူပြီး parameter မတူတဲ့ method များ) ဒါမှမဟုတ် လုံးဝ သီးခြား method တစ်ခု ဖြစ်ပါတယ်။
Overriding နဲ့ Overloading
ဒီနှစ်ခုကို မကြာခဏ ရောထွေးတတ်ပေမယ့် အခြေခံကျကျ မတူပါဘူး:
| Overriding | Overloading | |
|---|---|---|
| ဘယ်မှာလဲ | Child class က parent method ကို ပြန်ရေးတယ် | Class တစ်ခုတည်းမှာ နာမည်တူ method အများ ရေးတယ် |
| Parameter တွေ | Parent နဲ့ အတိအကျ တူရမယ် | မတူရဘူး (အရေအတွက် ဒါမှမဟုတ် type မတူ) |
| Return type | တူရမယ် (ဒါမှမဟုတ် subtype) | မတူလည်း ရတယ် |
| ဘယ်ဟာ run မလဲ | Runtime (program run နေစဉ်) မှာ ဆုံးဖြတ်တယ် (object ရဲ့ တကယ့် type ပေါ် မူတည်) | Compile time (compile လုပ်ချိန်) မှာ ဆုံးဖြတ်တယ် (parameter type တွေပေါ် မူတည်) |
| ရည်ရွယ်ချက် | Subtype အတွက် behaviour ကို သီးသန့် ပြင်ဖို့ | Operation (ဒေတာပေါ်မှာ လုပ်တဲ့ လုပ်ဆောင်ချက်) တစ်ခုတည်းကို ခေါ်နိုင်တဲ့ နည်း အများ ပေးဖို့ |
// OVERLOADING -- same class, different parameters
public class Calculator {
public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; }
public int add(int a, int b, int c) { return a + b + c; }
}
// OVERRIDING -- child class, same method signature
public class Animal {
public String speak() { return "..."; }
}
public class Dog extends Animal {
@Override
public String speak() { return "Woof!"; } // same name, same params
}
# OVERLOADING does not exist in Python - writing add() twice keeps only the LAST version.
# One method handles both ints and decimals (Python checks types at runtime):
class Calculator():
def add(self, a, b):
return a + b
# a three-number version would need a different name, e.g. add_three(a, b, c)
# OVERRIDING works exactly as in Java -- child class, same method name
class Animal():
def speak(self):
return "..."
class Dog(Animal):
def speak(self): # same name, no parameters - replaces the parent's version
return "Woof!"
Code ထဲက မှတ်ချက်တွေက ဒီလို ဆိုလိုပါတယ်: OVERLOADING က class တစ်ခုတည်းထဲမှာ parameter မတူတာ၊ OVERRIDING က child class ထဲမှာ method signature (method နာမည်နဲ့ parameter list) တူတာပါ။ Python မှာ overloading မရှိပါဘူး: add() ကို နှစ်ခါ ရေးရင် နောက်ဆုံး version ကိုပဲ ထားပါတယ်။ Method တစ်ခုတည်းက integer (ကိန်းပြည့်) ရော ဒသမ ကိန်းပါ ကိုင်တွယ်ပါတယ် (Python က type ကို run နေစဉ်မှာ စစ်ပါတယ်)၊ ဂဏန်း သုံးလုံး version အတွက်တော့ add_three(a, b, c) လို နာမည် မတူတာ လိုပါတယ်။
Overloading က polymorphism (ပုံစံ အမျိုးမျိုး ယူနိုင်ခြင်း) ရဲ့ static ပုံစံ (compile time မှာ ဆုံးဖြတ်တဲ့ ပုံစံ) ပါ။ အဲဒါက code ကို ဘယ်လို ထိရောက်စေလဲဆိုတာကို Static Polymorphism: Overloading မှာ ရှင်းပြထားပါတယ်။
Parent ရဲ့ version ကို super နဲ့ ခေါ်ခြင်း
တစ်ခါတလေ parent ရဲ့ behaviour ကို လုံးဝ အစားထိုးမယ့်အစား ဆက်ချဲ့ ချင်ပါတယ်။ Override လုပ်ထားတဲ့ method ထဲကနေ parent ရဲ့ version ကို ခေါ်ဖို့ super.methodName() ကို သုံးပါ:
public class Employee {
private String name;
private double baseSalary;
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
public double calculatePay() {
return baseSalary;
}
public String toString() {
return name + ": $" + calculatePay();
}
}
public class Manager extends Employee {
private double bonus;
public Manager(String name, double baseSalary, double bonus) {
super(name, baseSalary);
this.bonus = bonus;
}
@Override
public double calculatePay() {
return super.calculatePay() + bonus; // parent's pay + bonus
}
}
class Employee():
def __init__(self, name, base_salary):
self._name = name
self._base_salary = base_salary
def calculate_pay(self):
return self._base_salary
def __str__(self): # __str__ is Python's toString()
return self._name + ": $" + str(self.calculate_pay())
class Manager(Employee):
def __init__(self, name, base_salary, bonus):
super().__init__(name, base_salary) # call the parent constructor
self._bonus = bonus
def calculate_pay(self):
return super().calculate_pay() + self._bonus # parent's pay + bonus
Employee e = new Employee("Alice", 50000);
Manager m = new Manager("Bob", 60000, 10000);
System.out.println(e.calculatePay()); // 50000.0
System.out.println(m.calculatePay()); // 70000.0 (60000 + 10000)
e = Employee("Alice", 50000)
m = Manager("Bob", 60000, 10000)
print(e.calculate_pay()) # 50000 (Java's double prints 50000.0; a Python int stays 50000)
print(m.calculate_pay()) # 70000 (60000 + 10000)
Python code ထဲက မှတ်ချက်အရ Java ရဲ့ double က 50000.0 လို့ print ထုတ်ပေမယ့် Python ရဲ့ int ကတော့ 50000 အတိုင်း ရှိနေပါတယ်။
Manager ရဲ့ calculatePay() က super.calculatePay() ကနေတစ်ဆင့် parent ရဲ့ တွက်ချက်မှုကို ပြန်သုံးပြီး bonus ကို ထပ်ပေါင်းပါတယ်။ ဒီနည်းက base salary (အခြေခံ လစာ) တွက်တဲ့ logic ကို ထပ်ရေးစရာ မလိုအောင် လုပ်ပေးပါတယ်။
toString() Override (object ကို စာသားအဖြစ် ပြပုံကို အစားထိုး ရေးခြင်း)
Java class တိုင်းက Object (Java class အားလုံးရဲ့ အမြစ် class) ဆီကနေ toString() method ကို အမွေဆက်ခံပါတယ်။ ဘာမှ မပြင်ထားရင် အဲဒါက Student@1a2b3c လို အသုံးမဝင်တဲ့ စာသားကို ပြန်ပေးပါတယ်။ အဲဒါကို override လုပ်လိုက်ရင် object ကို အဓိပ္ပာယ်ရှိတဲ့ string (စာသား) အဖြစ် ဘယ်လို ပြမလဲ ကိုယ်တိုင် သတ်မှတ်နိုင်ပါတယ်:
public class Student {
private String name;
private int grade;
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
@Override
public String toString() {
return name + " (Grade " + grade + ")";
}
}
class Student():
def __init__(self, name, grade):
self._name = name
self._grade = grade
def __str__(self): # __str__ is Python's toString()
return self._name + " (Grade " + str(self._grade) + ")"
Student s = new Student("Alice", 11);
System.out.println(s); // Alice (Grade 11)
// Without override: Student@7a81197d
s = Student("Alice", 11)
print(s) # Alice (Grade 11)
# Without __str__: something like <__main__.Student object at 0x1024b5d90>
နောက်ဆုံး မှတ်ချက်တွေက override မလုပ်ထားရင် (Python မှာ __str__ မရှိရင်) ဘာ print ထွက်မလဲဆိုတာ ပြပါတယ်။
System.out.println() က object တွေပေါ်မှာ toString() ကို အလိုအလျောက် ခေါ်ပါတယ်။ အဲဒါကို override လုပ်ထားရင် debugging (program ထဲက အမှားကို ရှာပြီး ပြင်ခြင်း) နဲ့ output (program က ထုတ်ပြတဲ့ ရလဒ်) ထုတ်တာ အများကြီး ပိုလွယ်ပါတယ်။ (Python ရဲ့ print() ကလည်း __str__ ကို အတိအကျ အဲဒီလိုပဲ ခေါ်ပါတယ်။)
အဆင့်ဆင့် ရှင်းပြထားတဲ့ ဥပမာများ
ဥပမာ 1: Shape Hierarchy (ပုံသဏ္ဌာန် class တွေကို အဆင့်ဆင့် ဖွဲ့ထားပုံ)
public class Shape {
public double getArea() {
return 0;
}
public String describe() {
return "Shape with area " + getArea();
}
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double getArea() {
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 getArea() {
return width * height;
}
}
import math
class Shape():
def get_area(self):
return 0
def describe(self):
return "Shape with area " + str(self.get_area())
class Circle(Shape):
def __init__(self, radius):
self._radius = radius
def get_area(self):
return math.pi * self._radius * self._radius # math.pi is Java's Math.PI
class Rectangle(Shape):
def __init__(self, width, height):
self._width = width
self._height = height
def get_area(self):
return self._width * self._height
Circle c = new Circle(5);
Rectangle r = new Rectangle(4, 6);
System.out.println(c.describe()); // Shape with area 78.53981633974483
System.out.println(r.describe()); // Shape with area 24.0
c = Circle(5)
r = Rectangle(4, 6)
print(c.describe()) # Shape with area 78.53981633974483
print(r.describe()) # Shape with area 24 (ints multiply to an int; Java's double shows 24.0)
Python code ထဲက မှတ်ချက်အရ int နှစ်ခု မြှောက်ရင် int ရလို့ Python က 24 လို့ ပြပြီး Java ရဲ့ double ကတော့ 24.0 လို့ ပြပါတယ်။
describe() ကို override မလုပ်ထားပါဘူး: Circle က အဲဒါကို Shape ဆီကနေ အမွေဆက်ခံပါတယ်။ describe() က getArea() ကို ခေါ်ပြီး getArea() ကိုတော့ Circle က override လုပ်ထားပါတယ်။ ဒါကြောင့် c.describe() run တဲ့အခါ describe() ကိုယ်တိုင်က Shape ထဲမှာ ရေးထားတာ ဖြစ်ပေမယ့် Shape ရဲ့ getArea() ကို မဟုတ်ဘဲ Circle ရဲ့ getArea() ကို သုံးပါတယ်။
Quick Check (အမြန် စစ်ဆေးမေးခွန်း)
Q1. Method overriding ဆိုတာ ဘာလဲ။
Q2. @Override ကို ဘာကြောင့် သုံးသင့်သလဲ။
Q3. Parent မှာ void print(String s) ရှိပါတယ်။ Child က void print(int n) ကို ရေးပါတယ်။ ဒါက overriding လား။
Q4. Override လုပ်ထားတဲ့ method ထဲမှာ super.calculatePay() က ဘာလုပ်သလဲ။
Spot the Error (အမှား ရှာခြင်း)
ကျောင်းသား တစ်ယောက်က Dog ကို Animal ရဲ့ speak() method ကို override လုပ်စေချင်ပါတယ်၊ ဒါပေမယ့် code က compile မဖြစ်ပါဘူး: line 2 မှာ @Override က "method does not override or implement a method from a supertype" (parent class မှာ ကိုက်ညီတဲ့ method မရှိဘူး) ဆိုတဲ့ error ပြပါတယ်။ အမှားပါတဲ့ line ကို ရွေးပါ၊ ပြီးရင် ပြင်နည်းကို ရွေးပါ။
မှန်ကန်တဲ့ ပြင်နည်းကို ရွေးပါ:
Predict the Output (output ကို ကြိုခန့်မှန်းခြင်း)
အဓိက အယူအဆများ အပိုင်းက Employee/Manager class တွေကို သုံးပါ:
Manager m = new Manager("Bob", 60000, 10000);
System.out.println(m.calculatePay()); ဥပမာ 1 က Shape/Circle class တွေကို သုံးရင် c.describe() ရဲ့ output က ဘာနဲ့ စသလဲ။
Circle c = new Circle(5);
System.out.println(c.describe());Output က "Shape" နဲ့ စသလား၊ "Circle" နဲ့ စသလား။ အဖြေကို English လို ရိုက်ထည့်ပါ။
Practice Exercises (လေ့ကျင့်ခန်းများ)
Core (အခြေခံ အဆင့်)
-
toString() ကို override လုပ်ပါ: title (ခေါင်းစဉ်) နဲ့ author (စာရေးသူ) ပါတဲ့
Bookclass တစ်ခုကို ဖန်တီးပါ။"Title by Author"ကို ပြန်ပေးအောင်toString()ကို override လုပ်ပါ။ Book တစ်ခုကို ဖန်တီးပြီးSystem.out.println(book)နဲ့ တိုက်ရိုက် print ထုတ်ပါ။ -
Override လား overload လား ခွဲခြားပါ: အတွဲ တစ်တွဲစီအတွက် child method က parent ကို override လုပ်လား၊ overload လုပ်လား State (ဖော်ပြပါ) လုပ်ပါ:
- (a) Parent:
void draw()၊ Child:void draw() - (b) Parent:
int calculate(int x)၊ Child:int calculate(int x, int y) - (c) Parent:
String getName()၊ Child:String getName() - (d) Parent:
void print(String s)၊ Child:void print(int n)
- (a) Parent:
Extension (တိုးချဲ့ အဆင့်)
-
super နဲ့ ဆက်ချဲ့ပါ:
"Vehicle: [make]"ကို ပြန်ပေးတဲ့getDescription()ပါတဲ့Vehicleclass တစ်ခုကို ဖန်တီးပါ ([make]က ယာဉ်ထုတ်တဲ့ ကုမ္ပဏီ နာမည်ပါ)။ Parent ရဲ့ description နောက်မှာ" (4 doors)"ကို ဆက်ပြီး ပြန်ပေးအောင်getDescription()ကို override လုပ်တဲ့Carsubclass တစ်ခုကို ဖန်တီးပါ။super.getDescription()ကို သုံးပါ။ -
describe() ရဲ့ လှည့်ကွက်: ဥပမာ 1 မှာ
Shape.describe()ကgetArea()ကို ခေါ်ပါတယ်။describe()ကို Shape ထဲမှာ သတ်မှတ်ထားပေမယ့်c.describe()(c က Circle) က ဘာကြောင့် Circle ရဲ့getArea()ကို သုံးလဲ Explain (ရှင်းပြပါ) လုပ်ပါ။ ဘယ် OOP (object တွေကို အခြေခံပြီး program ရေးနည်း) principle (အခြေခံ သဘောတရား) က ဒါကို ဖြစ်စေတာလဲ။
Challenge (စိန်ခေါ်မှု အဆင့်)
- လစာ ပေးချေမှု စနစ်: Class hierarchy (class တွေကို အဆင့်ဆင့် ဖွဲ့ထားတဲ့ ပုံစံ) တစ်ခု ဖန်တီးပါ:
Employee(base salary: အခြေခံ လစာ)၊Manager(base + bonus: အခြေခံ လစာ + ဆုကြေး)၊SalesPerson(base + commission percentage * sales total: အခြေခံ လစာ + ကော်မရှင် ရာခိုင်နှုန်း * စုစုပေါင်း ရောင်းအား)။ အားလုံးကcalculatePay()ကို override လုပ်ပါတယ်။ Employee array (အရွယ်အစား ပုံသေ၊ အမျိုးအစားတူ ဒေတာစု) တစ်ခုကို ဖန်တီးပြီး type အမျိုးမျိုး ရောပြီး ဖြည့်ပါ၊ ပြီးရင် စုစုပေါင်း လစာ (total payroll) ကို တွက်ပါ။
ဆက်စပ် ခေါင်းစဉ်များ
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Inheritance (parent class ကနေ အမွေဆက်ခံခြင်း): override မလုပ်ခင်
extendsနဲ့superကို နားလည်ထားရပါမယ် - နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: Polymorphism (ပုံစံ အမျိုးမျိုး ယူနိုင်ခြင်း): overriding က polymorphic behaviour (object ရဲ့ type အလိုက် မတူတဲ့ လုပ်ဆောင်ပုံ) ကို ဖြစ်စေပါတယ်
- ဆက်စပ် ခေါင်းစဉ်: Constructors (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method များ): constructor overloading နဲ့ method overriding ကွာခြားချက်