Java Access Modifiers සිංහලෙන්: Public, Private, Protected, Default | SC Guide

Java Access Modifiers සිංහලෙන්: Public, Private, Protected, Default | SC Guide

ආයුබෝවන් යාළුවනේ! කොහොමද ඉතින්? අද අපි කතා කරන්න යන්නේ Java Programming වල ගොඩක්ම වැදගත්, හැබැයි සමහර වෙලාවට අලුතින් ඉගෙන ගන්න අයට පොඩ්ඩක් අවුල් වෙන්න පුළුවන් මාතෘකාවක් ගැන – ඒ තමයි Access Modifiers. විශේෂයෙන්ම Public, Private, Protected, Default කියන මේ සිව්දෙනා ගැන තමයි අපි ගැඹුරින්ම බලන්නේ. මේක Java වල විතරක් නෙවෙයි, Object-Oriented Programming (OOP) කරන අයට අත්‍යවශ්‍යම Concept එකක්. එහෙනම් වැඩේට බහිමු!

එකලස් කිරීමේ රහස: Encapsulation කියන්නේ මොකක්ද?

ඔන්න ඉස්සෙල්ලම අපි මේ Access Modifiers වලට පදනම දාන Encapsulation ගැන පොඩ්ඩක් කතා කරමු. Encapsulation කියන්නේ මොකක්ද? සරලව කිව්වොත්, අපේ Class එකක් ඇතුළේ තියෙන Data (variables) සහ ඒ Data එක්ක වැඩ කරන Methods එකට එකතු කරලා, ඒ Data වලට පිටින් Access කරන එක පාලනය කරන එකට. හරියට කැප්සියුලයක් වගේ. කැප්සියුලයක් ඇතුළේ බෙහෙත් තියෙනවා, හැබැයි අපිට ඒක කඩලා ඇතුළේ තියෙන බෙහෙත් කන්න බෑ, සම්පූර්ණ කැප්සියුල එකම තමයි ගිලින්න ඕනේ. ඒ වගේම තමයි අපේ Object එකේ ඇතුළේ තියෙන දේවල් පාලනය කරන එක තමයි Encapsulation වලින් වෙන්නේ.

මේකෙන් වෙන්නේ මොකක්ද? අපේ Code එකේ ආරක්ෂාව (Security) වැඩි වෙනවා, නිකරුණේ Data වෙනස් වීම් නවතිනවා, Code එක Maintain කරන්න පහසු වෙනවා. මොකද Class එකක Internal Data පිටස්තර Class වලට සෘජුවම Access කරන්න නොදී, Methods හරහා පමණක් Access කරන්න අවස්ථාව දීම නිසා, Data එකේ Integrity එක ආරක්ෂා වෙනවා. දැන් බලමු මේක කරන්න Access Modifiers කොහොමද උදව් වෙන්නේ කියලා.

1. Public: හැමෝටම පේන විදියට

පළවෙනියටම අපි කතා කරන්නේ Public ගැන. මේක තමයි Access Modifiers අතරින් ලේසිම එක. Public කියලා අපි යමක් Declare කළොත්, ඒක ඕනෙම Class එකකට, ඕනෙම Package එකකට Access කරන්න පුළුවන්. හරියට පාරේ යන බස් එකක් වගේ. ඕනෙම කෙනෙකුට ඒක බලන්නත්, පදින්නත් පුළුවන්. ඒ කියන්නේ Public Members (Variables, Methods, Constructors, Inner Classes) වලට කිසිම Access restriction එකක් නැහැ.

Public භාවිතය

අපි හිතමු අපිට Car කියලා Class එකක් තියෙනවා කියලා. ඒකේ model එක, start() method එක public කරලා තියෙනවා කියලා.

class Car {
    public String model; // Public variable
    public void start() { // Public method
        System.out.println("Car started!");
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.model = "Toyota Prius"; // Public නිසා direct access කරන්න පුළුවන්
        myCar.start(); // Public නිසා direct call කරන්න පුළුවන්
        System.out.println("My car model is: " + myCar.model);
    }
}

උඩ තියෙන Code එකේ model variable එකයි, start() method එකයි දෙකම public නිසා, Main Class එක ඇතුළේදී අපිට myCar.model කියලා ඒකට කෙලින්ම Access කරන්නත්, myCar.start() කියලා method එක Call කරන්නත් පුළුවන්. මේකෙන් වෙන්නේ ඕනෙම තැනකින් ඕනෙම කෙනෙකුට මේවා වෙනස් කරන්නත්, පාවිච්චි කරන්නත් පුළුවන් වීම. හැබැයි මේකෙන් Data Security එකට හානි වෙන්න පුළුවන්. ඒ නිසා Variables හැමවෙලේම Public නොකර ඉන්න එක හොඳයි.

2. Private: මගේ දේවල් මට විතරයි!

දෙවෙනියට එන්නේ Private. මේක තමයි Public එකේ සම්පූර්ණ විරුද්ධ පැත්ත. Private කියලා යමක් Declare කළොත්, ඒක Access කරන්න පුළුවන් වෙන්නේ ඒක Declare කරපු Class එක ඇතුළට විතරයි. ඒ කියන්නේ වෙනත් කිසිම Class එකකට (Subclass එකකටවත්) ඒ Private Members වලට කෙලින්ම Access කරන්න බෑ. හරියට අපේ ගෙදර ඇතුළේ තියෙන අපේ පෞද්ගලික කාමරයක් වගේ. ඒක ඇතුළට යන්න පුළුවන් අපිට විතරයි, නැත්නම් අපේ අවසරය තියෙන අයට විතරයි.

Private භාවිතය සහ Getters/Setters

ඇයි මේ Private පාවිච්චි කරන්නේ? මේක තමයි Encapsulation වල ප්‍රධානම අංගය. අපි Class එකක Data hide කරනවා. එහෙම Data hide කරලා, ඒ Data වලට පිටතින් Access කරන්න ඕන නම්, අපි public Methods හදනවා, ඒවට කියනවා Getters (අගය ගන්න) සහ Setters (අගය සකසන්න) කියලා. මේ Methods හරහා අපිට Data වලට Access කරන එක පාලනය කරන්න පුළුවන්, අවශ්‍ය Validations දාන්න පුළුවන්.

class BankAccount {
    private double balance; // Private variable

    public BankAccount(double initialBalance) {
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        } else {
            this.balance = 0; // Negative balance allow කරන්නේ නෑ
        }
    }

    // Getter method
    public double getBalance() {
        return balance;
    }

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

    public void withdraw(double amount) {
        if (amount > 0 && amount <= this.balance) {
            this.balance -= amount;
            System.out.println("Withdrew: " + amount + ". New balance: " + this.balance);
        } else {
            System.out.println("Invalid withdrawal amount or insufficient balance.");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount myAccount = new BankAccount(1000);
        // myAccount.balance = 5000; // Compile-time error! Private variable cannot be accessed directly

        System.out.println("Current balance: " + myAccount.getBalance()); // Access via getter

        myAccount.deposit(200);
        myAccount.withdraw(500);
        myAccount.withdraw(1000); // Invalid withdrawal attempt
        myAccount.deposit(-50); // Invalid deposit attempt

        System.out.println("Final balance: " + myAccount.getBalance());
    }
}

මේ BankAccount Class එකේ balance variable එක private නිසා, Main Class එකෙන් ඒකට කෙලින්ම Access කරන්න බෑ. ඒත් අපි getBalance(), deposit(), withdraw() වගේ public methods හරහා balance එකට Access කරන්න අවස්ථාව දීලා තියෙනවා. මේකෙන් වෙන්නේ අපේ balance එක සෘණ වෙන්න දෙන්නේ නැති වගේ Validations දාන්න පුළුවන් වීම. මේක තමයි හොඳම පුරුද්ද.

3. Protected: පවුලේ අයයි, කිට්ටු යාළුවොයි විතරයි

Protected කියන්නේ Private සහ Public අතරමැදි ස්වභාවයක් තියෙන එකක්. Protected කියලා Declare කරපු Member කෙනෙක්ව Access කරන්න පුළුවන් වෙන්නේ ඒ Member එක Declare කරපු Class එක ඇතුළෙදිමයි, එහෙමත් නැත්නම් ඒ Class එක Extend කරන Subclass වලටයි, ඒ වගේම එකම Package එකේ තියෙන අනිත් Class වලටයි විතරයි. හරියට අපේ පවුලේ අයයි, කිට්ටු යාළුවොයි විතරක් යන Party එකක් වගේ.

Protected භාවිතය: Inheritance (උරුමය) සමඟ

මේක ගොඩක්ම පාවිච්චි වෙන්නේ Inheritance (උරුමය) එක්ක තමයි. Parent Class එකක තියෙන දේවල් Child Class එකකට Access කරන්න දෙන්න ඕන නම්, හැබැයි ඒක පිටින් ඉන්න අයට (වෙනත් Package එකක, Subclass නොවන Class වලට) පේන්න දෙන්න ඕන නැත්නම්, Protected පාවිච්චි කරනවා.

// Package: com.mycompany.vehicles
package com.mycompany.vehicles;

public class Vehicle { // Class is public so it can be imported by other packages
    protected String brand = "Default Brand"; // Protected variable
    protected void honk() { // Protected method
        System.out.println("Tuut, tuut!");
    }
}

// Package: com.mycompany.vehicles (same package as Vehicle)
package com.mycompany.vehicles;

class Car extends Vehicle { // Car is in the same package and extends Vehicle
    private String modelName;

    public Car(String modelName) {
        this.modelName = modelName;
    }

    public void displayDetails() {
        System.out.println("Brand: " + brand); // OK: Accessing protected variable in subclass (same package)
        honk(); // OK: Accessing protected method in subclass (same package)
    }
}

// Different package: com.mycompany.app
package com.mycompany.app;

import com.mycompany.vehicles.Vehicle; // OK: Vehicle class is public

class Truck extends Vehicle { // Truck is in a different package but extends Vehicle
    public void printBrand() {
        System.out.println("Truck brand: " + brand); // OK: Accessing protected variable in subclass (different package)
    }
    public void activateHorn() {
        honk(); // OK: Accessing protected method in subclass (different package)
    }
}

public class Main {
    public static void main(String[] args) {
        // Example 1: Same package access (from Car class - though Main is in different package, Car's internal access works)
        com.mycompany.vehicles.Car myCar = new com.mycompany.vehicles.Car("Ford Focus");
        myCar.displayDetails();

        // Example 2: Different package, subclass access (from Truck class)
        Truck myTruck = new Truck();
        myTruck.printBrand();
        myTruck.activateHorn();

        // Example 3: Different package, non-subclass direct access (not allowed)
        Vehicle someVehicle = new Vehicle(); // OK: Vehicle class is public, so object can be created
        // someVehicle.brand = "Another Brand"; // Compile-time error! Cannot access protected directly from non-subclass in different package
        // someVehicle.honk(); // Compile-time error! Cannot access protected directly from non-subclass in different package
        System.out.println("\n--- Main Class එකට Protected Members වලට කෙලින්ම Access කරන්න බෑ --- ");
        System.out.println(" 'someVehicle.brand' සහ 'someVehicle.honk()' කියන Lines Compile-time errors ඇති කරයි.");
    }
}

මේ උදාහරණයේදී Vehicle Class එකේ brand එකයි, honk() method එකයි දෙකම protected. Vehicle Class එක public නිසා වෙනත් Package වලට එය import කරන්න පුළුවන්.

  • Car Class එක Vehicle එකේ Subclass එකක්. ඒ වගේම Car Class එකයි Vehicle Class එකයි දෙකම එකම Package එකේ (com.mycompany.vehicles) තියෙන නිසා brand එකටයි honk() method එකටයි පහසුවෙන් Access කරන්න පුළුවන්.
  • Truck Class එක Vehicle එකේ Subclass එකක්. හැබැයි Truck Class එක වෙනත් Package එකක (com.mycompany.app) තියෙන්නේ. එහෙම වුණත්, Truck Class එක Vehicle එක Extend කරන නිසා, protected member වලට Access කරන්න පුළුවන්.
  • හැබැයි, Main Class එකේදී Vehicle Object එකක් හදලා ඒකේ protected members වලට කෙලින්ම Access කරන්න බෑ, මොකද Main Class එක Vehicle එකේ Subclass එකක් නොවන නිසා සහ වෙනත් Package එකක තියෙන නිසා.

4. Default (Package-Private): කවුරුත් කිව්වේ නැත්නම් මොකද වෙන්නේ?

මේකට කියන්නේ Default Access Modifier කියලා. මේක අපි විශේෂයෙන්ම Keyword එකක් දාලා Declare කරන්නේ නෑ. අපි කිසිම Access Modifier එකක් දැම්මේ නැත්නම්, Java Compiler එක විසින් ඒකට Default Access Modifier එක දානවා. මේක Package-Private කියලත් හඳුන්වනවා.

Default Access Modifier භාවිතය

Default Access Modifier එකෙන් කියන්නේ, ඒ Member කෙනෙක්ව Access කරන්න පුළුවන් වෙන්නේ ඒක Declare කරපු Class එක ඇතුළට විතරයි, නැත්නම් ඒක තියෙන Package එකේ තියෙන අනිත් Class වලට විතරයි. Package එකෙන් පිටත Class වලට Access කරන්න බෑ. හරියට අපේ ගමේ යාළුවෝ ටික විතරක් යන Trip එකක් වගේ. ගමේ අය විතරයි එතැනට එන්නේ.

// Package: com.mycompany.core
package com.mycompany.core;

// No access modifier means default (package-private) for the class itself
class DataProcessor {
    String internalData = "Secret Information"; // Default (Package-private)
    void process() { // Default (Package-private) method
        System.out.println("Processing: " + internalData);
    }
}

// In the same package as DataProcessor
package com.mycompany.core;

class Utility { // Also default access
    void useProcessor() {
        DataProcessor processor = new DataProcessor(); // OK: DataProcessor is in the same package
        System.out.println("Accessing from same package: " + processor.internalData); // OK: Same package
        processor.process(); // OK: Same package
    }
}

// Package: com.mycompany.app (Different package)
package com.mycompany.app;

// import com.mycompany.core.DataProcessor; // Compile-time error! Cannot import default class from different package
// import com.mycompany.core.Utility; // Compile-time error! Cannot import default class from different package

public class Main {
    public static void main(String[] args) {
        System.out.println("\n--- Default Class/Members වෙනත් Package එකක සිට Access කිරීම --- ");
        // DataProcessor processor = new DataProcessor();
        // උඩින් තියෙන Line එක Compile-time error එකක් ඇති කරයි. මොකද DataProcessor Class එක Default
        // Access Modifier එකකින් තියෙන්නේ. ඒ නිසා වෙනත් Package එකකට මේක Access කරන්න බෑ.
        System.out.println("DataProcessor class එක Default Access නිසා, වෙනත් Package එකකින් Object හදන්න බැහැ.");
        System.out.println("DataProcessor class එක public වුණත්, එහි 'internalData' සහ 'process()' (Default) Members වෙනත් Package එකකට Access කරන්න බැහැ.");
        
        // com.mycompany.core.Utility utility = new com.mycompany.core.Utility();
        // Utility Class එකත් Default Access නිසා, මේකත් Compile-time error එකක් ඇති කරයි.
        System.out.println("ඒ වගේම, Utility Class එකත් Default Access නිසා, එයත් මේ Package එකෙන් සෘජුව භාවිතා කරන්න බැහැ.");
    }
}

මේ උදාහරණයේදී, DataProcessor Class එකම Default Access Modifier එකෙන් තියෙන්නේ. ඒ නිසා com.mycompany.app කියන වෙනත් Package එකක තියෙන Main Class එකට DataProcessor Class එක import කරන්නවත්, එහි Object එකක් හදන්නවත් බෑ.

Utility Class එක DataProcessor Class එකත් එක්ක එකම Package එකේ (com.mycompany.core) තියෙන නිසා, ඒවට Access කරන්න පුළුවන්. ඒ වගේම Utility Class එකත් Default Access එකක් තියෙන නිසා, එයත් com.mycompany.app Package එකෙන් Access කරන්න බෑ.

මතක තියාගන්න, Class එකකට Default Access Modifier එකක් තියෙනවා නම්, ඒක Package එකෙන් පිටතදී import කරන්නවත්, Object හදන්නවත් බෑ.

ප්‍රයෝගික උපදෙස් සහ හොඳම පුරුදු (Best Practices)

Access Modifiers හරියට පාවිච්චි කරන එක ඔබේ Code එකේ Quality එකට ගොඩක් වැදගත්. මෙන්න ඒ සඳහා උපදෙස් කීපයක්:

  • Data Hiding (තොරතුරු සැඟවීම): හැමවෙලේම Variables private කරන්න පුරුදු වෙන්න. ඒක තමයි Encapsulation වලට ගොඩක්ම උදව් වෙන්නේ. මේකෙන් Data corruption වෙන එක නවත්වන්න පුළුවන්.
  • Getters/Setters පාවිච්චිය: private Variables වලට Access කරන්න ඕන නම්, public Getters සහ Setters පාවිච්චි කරන්න. මේකෙන් Data Validations දාන්න පුළුවන්කම ලැබෙනවා.
  • Methods: Class එකක Core functionality එක පෙන්වන Methods public කරන්න. හැබැයි Helper Methods (අනිත් Methods වලට උදව් කරන, නමුත් පිටතින් Direct Call කරන්න අවශ්‍ය නැති Methods) නම් private හෝ protected කරන්න.
  • Default Access Modifier ගැන සැලකිලිමත් වීම: ඔබ විශේෂයෙන්ම කිසිම Modifier එකක් නොදාන අවස්ථා වලදී Default Access Modifier එක ක්‍රියාත්මක වෙන බව මතක තියාගන්න. සමහර වෙලාවට මේකෙන් unexpected behaviour ඇති වෙන්න පුළුවන්, විශේෂයෙන්ම Class, Interface හෝ Enum එකක් Declare කරන විට.
  • Protected: උරුමය සඳහා පමණයි: protected පාවිච්චි කරන්න ඕන නම්, ඒක Inheritance එක්ක විතරක් පාවිච්චි කරන්න. ඒ කියන්නේ Subclasses වලට Parent Class එකේ දේවල් Access කරන්න දෙන්න ඕන නම් විතරයි. අනවශ්‍ය විදියට protected පාවිච්චි නොකර ඉන්න.
  • සරලව සිතීම: Access Modifiers තෝරගන්නකොට, හැමවෙලේම අවම Access Level එක පාවිච්චි කරන්න බලන්න. ඒ කියන්නේ private වලින් පටන් අරන්, අවශ්‍ය නම් විතරක් default, protected, public වලට යන්න.

නිගමනය

ඉතින් යාළුවනේ, මේ තමයි Java වල Access Modifiers ගැන සරලව කිව්වොත් තොරතුරු ටික. මේවා Java Programming වලදී අත්‍යවශ්‍ය මූලික සංකල්ප. Encapsulation කියන Object-Oriented Programming (OOP) Concept එක තේරුම් ගන්නත්, හොඳ Design Patterns පාවිච්චි කරන්නත් මේ Access Modifiers ගැන හොඳ අවබෝධයක් තියෙන්න ඕනේ. මේවා පාවිච්චි කරලා, ඔයාලට පුළුවන් Cleaner, Safer, සහ Maintain කරන්න පහසු Code ලියන්න.

මේවා තියරියට විතරක් තේරුම් ගත්තට මදි, අනිවාර්යයෙන්ම මේ Code Examples ඔයාලගේ IDE (IntelliJ, Eclipse, VS Code වගේ) එකේ Run කරලා බලන්න. ඒ වගේම විවිධ Access Modifiers දාලා මොකද වෙන්නේ කියලා Experiment කරන්න. ඔයාලගේ අදහස්, ප්‍රශ්න පහළින් Comment කරන්න. තව මොනවා ගැනද දැනගන්න කැමති කියලත් කියන්න. එහෙනම් තවත් අලුත් Topic එකකින් හමුවෙමු! Happy Coding!