Java Method Overriding | Super Keyword Explained in Sinhala - SC Guide

Java Method Overriding | Super Keyword Explained in Sinhala - SC Guide

කොහොමද යාලුවනේ! Java Method Overriding සහ super Keyword ගැන දැනගමු

අද අපි කතා කරන්න යන්නේ Java වල OOP concepts අතරින් ගොඩක් වැදගත්, හැබැයි සමහරුන්ට අවුල් වෙන 'Method Overriding' කියන එකයි, ඒකත් එක්කම එන 'super' keyword එකයි ගැනයි. Java කියන්නේ අපේ රටේ විතරක් නෙවෙයි, ලෝකෙම ගොඩක් ජනප්‍රිය programming language එකක්නේ. විශේෂයෙන්ම software development පැත්තට යන අයට OOP concepts හරියට තේරුම් ගන්න එක අනිවාර්යයි.

මොකද, object-oriented programming (OOP) කියන්නේ Java වල හදවත. Inheritance, Polymorphism, Abstraction, Encapsulation වගේ දේවල් හරියට තේරුම් ගත්තොත් විතරයි අපිට හොඳ quality code එකක් ලියන්න පුළුවන් වෙන්නේ. මේ ලිපියෙන් අපි බලමු Method Overriding කියන්නේ මොකක්ද, ඒකෙන් අපිට ලැබෙන වාසි මොනවද, ඒ වගේම super keyword එක කොහොමද මේ වැඩේට උදව් වෙන්නේ කියලා.

කෙලින්ම වැඩේට බහිමු එහෙනම්!

Method Overriding කියන්නේ මොකක්ද? (What is Method Overriding?)

සරලවම කිව්වොත්, Method Overriding කියන්නේ parent class (super class) එකක තියෙන method එකක්, child class (subclass) එකකදී ඒ method එකටම වෙනස් implementation එකක් (වෙනස් විදියකට ක්‍රියාත්මක වීමක්) දෙන එක. හිතන්නකෝ ඔයාලගේ තාත්තාට 'ඇවිදිනවා' කියන හැකියාව තියෙනවා කියලා. ඔයාලත් 'ඇවිදිනවා' කියන හැකියාව inherit කරනවා (උරුම කරගන්නවා). හැබැයි ඔයාලට පුළුවන් ඒ ඇවිදින විදිය ටිකක් වෙනස් කරගන්න (faster or slower). ඒක තමයි Method Overriding.

මේකෙන් වෙන්නේ, parent class එකේදී සාමාන්‍යයෙන් කරන වැඩේ child class එකට අවශ්‍ය විදියට වෙනස් කරගන්න පුළුවන් වෙන එක. මේක විශේෂයෙන්ම Polymorphism කියන OOP concept එකට අදාළයි. Polymorphism කියන්නේ 'බහුරූපී බව' (many forms) කියන එකනේ. ඒ කියන්නේ එකම method එකකට විවිධ objects අනුව විවිධ විදියට ක්‍රියා කරන්න පුළුවන්.

Method Overriding වලට අවශ්‍ය නීති (Rules for Method Overriding):

  • Method Signature එක එකම වෙන්න ඕනේ: Override කරන method එකේ නම (method name) සහ parameters (arguments) parent class එකේ method එකේ වගේම අනිවාර්යයෙන්ම එකම විදියට තියෙන්න ඕනේ.
  • Return Type එක එකම වෙන්න ඕනේ: Return type එකත් parent class එකේ method එකේ return type එකම වෙන්න ඕනේ. (Java 5 න් පස්සේ covariant return types support කරනවා, ඒ කියන්නේ child class එකේ return type එක parent class එකේ return type එකේ subclass එකක් වෙන්න පුළුවන්).
  • Access Modifier එක සමාන හෝ අඩු restrictive වෙන්න ඕනේ: Child class එකේ override කරන method එකේ access modifier එක parent class එකේ method එකේ access modifier එකට වඩා restrict වෙන්න බැහැ. උදාහරණයක් විදියට, parent class එකේ method එක protected නම්, child class එකේදී ඒක private කරන්න බැහැ. public හෝ protected කරන්න පුළුවන්.
  • private methods Override කරන්න බැහැ: private methods inherit වෙන්නේ නැති නිසා ඒවා Override කරන්න බැහැ.
  • final methods Override කරන්න බැහැ: final කියන්නේ ඒ method එකේ implementation එක තවදුරටත් වෙනස් කරන්න බැහැ කියන එක. ඒ නිසා final methods Override කරන්න බැහැ.
  • static methods Override කරන්න බැහැ: static methods Class එකට අදාළ මිසක් Objects වලට නෙවෙයි. ඒ නිසා static methods Override වෙන්නේ නැහැ. (ඒවා Method Hiding කියලා කියනවා).

උදාහරණයක් (Example):

class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

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

public class OverridingDemo {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        myAnimal.makeSound(); // Output: Animal makes a sound

        Dog myDog = new Dog();
        myDog.makeSound();    // Output: Dog barks

        Animal anotherAnimal = new Dog(); // Polymorphism in action
        anotherAnimal.makeSound(); // Output: Dog barks
    }
}

මේ උදාහරණයේදී, Animal class එකට makeSound() කියන method එක තියෙනවා. Dog class එක Animal class එකෙන් inherit කරනවා (extend කරනවා). ඒ වගේම Dog class එකේ makeSound() method එක Override කරලා තියෙනවා. ඒ නිසා Dog object එකක් makeSound() call කරද්දී, Dog class එකේ implementation එක ක්‍රියාත්මක වෙනවා. ඒ වගේම, Animal anotherAnimal = new Dog(); කියලා Dog object එකක් Animal type එකකින් refer කරත්, makeSound() call කරද්දී ක්‍රියාත්මක වෙන්නේ Dog class එකේ Override කරපු method එක. මේක තමයි Dynamic Method Dispatch, නැත්නම් Run-time Polymorphism කියලා කියන්නේ.

Method Overriding වලින් ලැබෙන වාසි (Benefits of Method Overriding)

හරි, දැන් Method Overriding කියන්නේ මොකක්ද කියලා තේරුණානේ. දැන් බලමු මේකෙන් අපිට ලැබෙන වාසි මොනවද කියලා:

  • Runtime Polymorphism: මේක තමයි ප්‍රධානම වාසිය. අපිට පුළුවන් එකම method call එකකින් විවිධ objects වලට විවිධ විදියට ක්‍රියා කරන්න සලස්වන්න. මේකෙන් code එක වඩාත් flexible සහ extensible වෙනවා.
  • Code Flexibility: Child classes වලට තමන්ටම වෙන්වූ විශේෂ හැසිරීම් (specific behaviors) define කරන්න පුළුවන්, parent class එකේ code එකට අත නොතියාම.
  • Code Reusability: Parent class එකේ පොදු implementation එකක් තියෙනවා නම්, child classes වලට ඒක inherit කරලා අවශ්‍ය තැන් විතරක් වෙනස් කරන්න පුළුවන්. ඒ කියන්නේ මුල ඉඳන්ම method එකක් ලියන්න ඕනේ නැහැ.
  • Enhancing functionality: අපිට පුළුවන් parent class එකේ method එකක functionality එක child class එකේදී තවත් වැඩි කරන්න. (super keyword එක පාවිච්චි කරලා parent method එක call කරලා, ඒකට අලුත් functionality එකක් add කරන්න පුළුවන්.)

super Keyword එකේ බලය (The Power of the super Keyword)

super කියන්නේ Java වල තියෙන විශේෂ keyword එකක්. මේක පාවිච්චි කරන්නේ immediate parent class object එක refer කරන්න. ඒ කියන්නේ, අපිට child class එකක් ඇතුළේ ඉඳන් parent class එකේ members (variables, methods, constructors) access කරන්න අවශ්‍ය වුණොත් තමයි super keyword එක පාවිච්චි කරන්නේ.

super keyword එක ප්‍රධාන වශයෙන් තැන් තුනකදී පාවිච්චි කරනවා:

1. Parent class එකේ Instance Variables (Fields) Access කරන්න:

සමහර වෙලාවට parent class එකේ variable name එකයි child class එකේ variable name එකයි එකම වෙන්න පුළුවන්. මේ වගේ අවස්ථාවකදී child class එකේ method එකක් ඇතුළේදී parent class එකේ variable එක access කරන්න super keyword එක පාවිච්චි කරනවා. නැත්නම් Java compiler එක automatically current class එකේ variable එක choose කරනවා.

class Vehicle {
    String type = "Generic Vehicle";
}

class Car extends Vehicle {
    String type = "Sedan";

    public void displayType() {
        System.out.println("Car type: " + type);        // Refers to Car's 'type'
        System.out.println("Vehicle type: " + super.type); // Refers to Vehicle's 'type'
    }
}

public class SuperVariableDemo {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.displayType();
        // Output:
        // Car type: Sedan
        // Vehicle type: Generic Vehicle
    }
}

2. Parent class එකේ Methods invoke කරන්න:

අපි Method Overriding ගැන කතා කරද්දී කිව්වානේ child class එකේදී parent method එක Override කරනවා කියලා. හැබැයි සමහර වෙලාවට අපිට ඕනේ වෙනවා Overridden method එක ඇතුළේ ඉඳන්ම parent class එකේ original method එකත් call කරන්න. ඒ වෙලාවට super.methodName() කියලා පාවිච්චි කරන්න පුළුවන්.

class Person {
    void eat() {
        System.out.println("Person is eating.");
    }
}

class Student extends Person {
    @Override
    void eat() {
        System.out.println("Student is eating at cafeteria.");
        super.eat(); // Calls the eat() method of the Person class
    }
}

public class SuperMethodDemo {
    public static void main(String args[]) {
        Student s = new Student();
        s.eat();
        // Output:
        // Student is eating at cafeteria.
        // Person is eating.
    }
}

මේක ගොඩක් ප්‍රයෝජනවත්, මොකද අපිට පුළුවන් parent class එකේ පොදු functionality එකක් තියාගෙන, child class එකේදී ඒකට අමතර දේවල් එකතු කරන්න.

3. Parent class එකේ Constructors invoke කරන්න:

super() කියන්නේ parent class එකේ constructor එක call කරන්න පාවිච්චි කරන method එකක්. මේක child class එකේ constructor එකේ පළවෙනි statement එක විදියටම තියෙන්න ඕනේ. අපි explicit විදියට super() call නොකළොත්, Java compiler එක default constructor එක (no-argument constructor) automatically call කරනවා. ඒත් parent class එකට no-argument constructor එකක් නැත්නම් (ඒ කියන්නේ arguments තියෙන constructor එකක් විතරක් තියෙනවා නම්), අපි අනිවාර්යයෙන්ම super(arguments) කියලා call කරන්න ඕනේ.

class LivingBeing {
    LivingBeing() {
        System.out.println("LivingBeing constructor called");
    }
    LivingBeing(String name) {
        System.out.println("LivingBeing constructor with name: " + name);
    }
}

class Human extends LivingBeing {
    Human() {
        // super(); // Implicitly called by compiler if not explicitly mentioned
        System.out.println("Human constructor called");
    }

    Human(String name) {
        super(name); // Calls the LivingBeing(String name) constructor
        System.out.println("Human constructor with name: " + name);
    }
}

public class SuperConstructorDemo {
    public static void main(String args[]) {
        Human h1 = new Human();
        // Output:
        // LivingBeing constructor called
        // Human constructor called

        System.out.println("\n---");

        Human h2 = new Human("John Doe");
        // Output:
        // LivingBeing constructor with name: John Doe
        // Human constructor with name: John Doe
    }
}

මතක තියාගන්න, super() call එක constructor එකක පළමු statement එක වෙන්නම ඕනේ. ඒ වගේම එක constructor එකක් ඇතුළේ එක super() call එකක් විතරයි තියෙන්න පුළුවන්.

ප්‍රායෝගික උදාහරණයක් (Practical Example)

දැන් අපි බලමු මේ Method Overriding සහ super keyword එක එකට පාවිච්චි කරන්නේ කොහොමද කියලා තවත් ප්‍රායෝගික උදාහරණයකින්.

හිතන්නකෝ අපිට bank accounts ටිකක් handle කරන්න system එකක් හදනවා කියලා. අපිට පොදු Account class එකක් තියෙනවා deposit සහ withdraw methods එක්ක. ඊට පස්සේ SavingsAccount සහ CurrentAccount වගේ subclass එකක් තියෙනවා, ඒවට පොඩි පොඩි වෙනස්කම් තියෙනවා withdraw method එකේ.

class Account {
    double balance;

    Account(double balance) {
        this.balance = balance;
        System.out.println("Account created with balance: " + this.balance);
    }

    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: " + amount + ". New balance: " + balance);
        } else {
            System.out.println("Deposit amount must be positive.");
        }
    }

    void withdraw(double amount) {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            System.out.println("Withdrew: " + amount + ". New balance: " + balance);
        } else {
            System.out.println("Insufficient balance or invalid amount. Current balance: " + balance);
        }
    }

    double getBalance() {
        return balance;
    }
}

class SavingsAccount extends Account {
    double interestRate;

    SavingsAccount(double balance, double interestRate) {
        super(balance); // Call parent class constructor
        this.interestRate = interestRate;
        System.out.println("Savings Account created with interest rate: " + this.interestRate);
    }

    // Overriding withdraw method with a minimum balance check
    @Override
    void withdraw(double amount) {
        if (balance - amount < 1000) { // Minimum balance of 1000
            System.out.println("Cannot withdraw. Minimum balance of 1000 must be maintained. Current balance: " + balance);
        } else {
            super.withdraw(amount); // Call parent class's withdraw method
        }
    }

    void addInterest() {
        double interest = balance * interestRate / 100;
        balance += interest;
        System.out.println("Interest added: " + interest + ". New balance: " + balance);
    }
}

class CurrentAccount extends Account {
    double overdraftLimit;

    CurrentAccount(double balance, double overdraftLimit) {
        super(balance);
        this.overdraftLimit = overdraftLimit;
        System.out.println("Current Account created with overdraft limit: " + this.overdraftLimit);
    }

    // Overriding withdraw method to allow overdraft
    @Override
    void withdraw(double amount) {
        if (amount > 0 && (balance + overdraftLimit) >= amount) {
            balance -= amount;
            System.out.println("Withdrew: " + amount + ". New balance: " + balance + " (Overdraft limit used: " + (balance < 0 ? Math.abs(balance) : 0) + ")");
        } else {
            System.out.println("Withdrawal failed. Exceeds overdraft limit or invalid amount. Current balance: " + balance);
        }
    }
}

public class BankAccountDemo {
    public static void main(String[] args) {
        System.out.println("--- Savings Account ---");
        SavingsAccount savings = new SavingsAccount(5000, 5);
        savings.withdraw(3000); // Fails due to minimum balance
        savings.withdraw(1000); // Success
        savings.addInterest();
        System.out.println("Final Savings Balance: " + savings.getBalance());

        System.out.println("\n--- Current Account ---");
        CurrentAccount current = new CurrentAccount(2000, 1000);
        current.withdraw(2500); // Success with overdraft
        current.withdraw(1000); // Fails (exceeds overdraft)
        System.out.println("Final Current Balance: " + current.getBalance());

        System.out.println("\n--- Polymorphism Example ---");
        Account polyAccount1 = new SavingsAccount(8000, 4);
        polyAccount1.withdraw(7500); // SavingsAccount's withdraw logic applies (fails)

        Account polyAccount2 = new CurrentAccount(1500, 500);
        polyAccount2.withdraw(1800); // CurrentAccount's withdraw logic applies (success)
    }
}

මේ උදාහරණයෙන් පේනවානේ, SavingsAccount එකේ withdraw method එක Account එකේ withdraw method එක Override කරලා තියෙනවා, අවම ශේෂය (minimum balance) බලන්න. ඊට පස්සේ, අවම ශේෂය ගැටලුවක් නැත්නම්, super.withdraw(amount); කියලා parent class එකේ original withdraw method එක call කරනවා. ඒ වගේම CurrentAccount එකත් withdraw method එක Override කරලා තියෙනවා overdraft limit එකක් එක්ක වැඩ කරන්න. ඒ වගේම, constructors වලදී super(balance); කියලා parent class constructor එක call කරලා තියෙනවා. මේකෙන් අපිට පුළුවන් code එක clean විදියට තියාගෙන, එක් එක් account type එකට අදාළව වෙනස් operations handle කරන්න.

නිගමනය (Conclusion)

හරි, දැන් ඔයාලට Java වල Method Overriding සහ super keyword එක ගැන හොඳ අවබෝධයක් ලැබිලා ඇති කියලා හිතනවා. මේ concepts දෙකම Java OOP වලදී අත්‍යවශ්‍යයි. ඒවා හරියට තේරුම් ගත්තොත් ඔයාලට වඩාත් effective විදියට code ලියන්නත්, complex systems design කරන්නත් පුළුවන් වෙනවා.

  • Method Overriding වලින් අපිට parent class එකේ method එකක් child class එකේ අවශ්‍යතා අනුව වෙනස් කරන්න පුළුවන්. මේකෙන් Run-time Polymorphism කියන concept එක සාක්ෂාත් වෙනවා.
  • super keyword එකෙන් අපිට child class එකක් ඇතුළේ ඉඳන් parent class එකේ variables, methods, සහ constructors access කරන්න පුළුවන්.

දැන් ඔයාලට මේ concepts පැහැදිලි ඇති කියලා හිතනවා. පුළුවන් තරම් practice කරන්න, පොඩි පොඩි program ලියලා බලන්න. එතකොට තමයි මේවා ඔලුවට හරියටම යන්නේ. මොනවා හරි ප්‍රශ්න තියෙනවා නම්, comment එකක් දාන්න අමතක කරන්න එපා. ඊළඟට මොකක් ගැනද කතා කරන්න ඕනේ කියලත් කියන්න!

එහෙනම් ආයෙත් අලුත් ලිපියකින් හම්බවෙමු! සුභ දවසක්!