Static Members (class ကိုယ်တိုင် ပိုင်တဲ့ member များ)
B3.1: Distinguish between static and instance members.
မြန်မာလို: static member (class ကိုယ်တိုင် ပိုင်တဲ့ attribute နဲ့ method) နဲ့ instance member (object တစ်ခုချင်းစီ ပိုင်တဲ့ attribute နဲ့ method) တို့ကြား ကွာခြားချက်ကို ခွဲခြားနိုင်ရပါမယ်။
အဓိက အယူအဆများ
Instance နဲ့ Static: အဓိက ကွာခြားချက်
Class (object တွေ ဖန်တီးဖို့ ပုံစံခွက်) တစ်ခုထဲက အရာတိုင်းက instance (object တစ်ခုချင်းစီက ပိုင်တဲ့) ဒါမှမဟုတ် static (class ကိုယ်တိုင်က ပိုင်တဲ့) ဖြစ်ပါတယ်။
| Instance | Static | |
|---|---|---|
| ဘယ်သူ ပိုင်လဲ | Object တစ်ခုချင်းစီ | Class ကိုယ်တိုင် |
| Copy ဘယ်နှစ်ခု ရှိလဲ | Object တစ်ခုကို တစ်ခုစီ | တစ်ခုတည်း အတိအကျ၊ object အားလုံး မျှသုံးပါတယ် |
| ဘာနဲ့ သုံးလဲ | Object reference (object ရှိရာ memory နေရာကို ညွှန်းတဲ့ တန်ဖိုး): obj.method() | Class နာမည်: ClassName.method() |
| ဘာကို သုံးနိုင်လဲ | Instance member + static member | Static member ကို တိုက်ရိုက်၊ instance member ကိုတော့ object တစ်ခုကနေတစ်ဆင့်သာ |
this ရှိလား | ရှိပါတယ် | မရှိပါ |
Static Variables (class တစ်ခုလုံး မျှသုံးတဲ့ variable များ)
Static variable (class variable လို့လည်း ခေါ်ပါတယ်) ကို class ရဲ့ object အားလုံးက မျှသုံးပါတယ်။ Object ဘယ်နှစ်ခု ရှိရှိ copy တစ်ခုတည်းပဲ ရှိပါတယ်။ Object တစ်ခုက ပြောင်းလိုက်ရင် object အားလုံးက အဲဒီ ပြောင်းလဲမှုကို မြင်ရပါတယ်။
အသုံးအများဆုံး နေရာ: object ဘယ်နှစ်ခု ဖန်တီးပြီးပြီလဲ ရေတွက်ခြင်း။
public class Student {
private String name;
private static int count = 0; // shared by ALL Student objects
public Student(String name) {
this.name = name;
count++; // every new Student increments the same counter
}
public String getName() { return name; }
public static int getCount() { return count; }
}
class Student():
count = 0 # class attribute - defined at class level, shared by ALL Students
def __init__(self, name):
self._name = name
Student.count = Student.count + 1 # every new Student updates the same counter
def get_name(self):
return self._name
def get_count(): # no self - the method belongs to the class
return Student.count # (Python often marks these with a decorator;
# IB keeps the simple bare form shown here)
Student s1 = new Student("Alice");
Student s2 = new Student("Bob");
Student s3 = new Student("Charlie");
System.out.println(Student.getCount()); // 3
System.out.println(s1.getName()); // Alice
s1 = Student("Alice")
s2 = Student("Bob")
s3 = Student("Charlie")
print(Student.get_count()) # 3 - called on the class name, not an object
print(s1.get_name()) # Alice
count ကို မျှသုံးပါတယ်: ကျောင်းသား တစ်ယောက်ကို counter (အရေအတွက် မှတ်တဲ့ variable) တစ်ခုစီ မဟုတ်ဘဲ class တစ်ခုလုံးအတွက် counter တစ်ခုတည်း ရှိပါတယ်။ name က instance ပါ: ကျောင်းသား တစ်ယောက်စီမှာ ကိုယ်ပိုင် name ရှိပါတယ်။
Static Methods (class ကိုယ်တိုင် ပိုင်တဲ့ method များ)
Static method ကို ဘယ် object ကမှ မပိုင်ဘဲ class က ပိုင်ပါတယ်။ Object reference နဲ့ မဟုတ်ဘဲ class နာမည်နဲ့ ခေါ်ပါတယ်။ သူ့မှာ this မရှိလို့ instance variable (object တစ်ခုချင်းရဲ့ ကိုယ်ပိုင် variable) တွေကို မသုံးနိုင်သလို instance method (object တစ်ခုပေါ်မှာ ခေါ်ရတဲ့ method) တွေကိုလည်း မခေါ်နိုင်ပါဘူး: သူ အလုပ်လုပ်ပေးနေတဲ့ သတ်မှတ်ထားတဲ့ object တစ်ခု မရှိလို့ပါ။
public class MathHelper {
public static int square(int n) {
return n * n;
}
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
}
class MathHelper():
def square(n): # no self - operates only on its parameter
return n * n
def max(a, b): # safe here: MathHelper.max does not replace Python's built-in max
if a >= b:
return a
return b
// Called on the class, not on an object
int result = MathHelper.square(5); // 25
int bigger = MathHelper.max(3, 7); // 7
# Called on the class, not on an object
result = MathHelper.square(5) # 25
bigger = MathHelper.max(3, 7) # 7
Static method တွေကို နေ့တိုင်း သုံးနေပြီးသားပါ:
Math.random(): Math object မလိုပါဘူးMath.sqrt(16): ဒီ method က Math class ပိုင်ပါတယ်Integer.parseInt("42"): String ကို int အဖြစ် ပြောင်းပေးပါတယ်System.out.println():outကSystemclass ရဲ့ static field (class ထဲမှာ ကြေညာထားတဲ့ static variable) ပါ
main က ဘာကြောင့် static ဖြစ်သလဲ
public static void main(String[] args)
# Python has no main method. Top-level code runs as soon as the
# file is executed - no objects and no special entry point needed.
main (program စ run တဲ့ method) က program ရဲ့ ဝင်ပေါက် (entry point) ဖြစ်လို့ static ဖြစ်ပါတယ်: object တစ်ခုမှ မရှိသေးခင် run ပါတယ်။ main က instance method ဖြစ်ခဲ့ရင် Java က သူ့ကို ခေါ်ဖို့ object တစ်ခု လိုပါလိမ့်မယ်၊ ဒါပေမယ့် program စချိန်မှာ object တစ်ခုမှ မရှိသေးပါဘူး။ static လုပ်ထားလို့ Java က class ပေါ်မှာ တိုက်ရိုက် ခေါ်လို့ ရပါတယ်။
Static method တွေ မလုပ်နိုင်တဲ့ အရာများ
Static method မှာ this reference မရှိပါဘူး။ ဒါကြောင့် ဒါတွေကို မလုပ်နိုင်ပါဘူး:
public class Student {
private String name;
private static int count = 0;
// This WON'T compile:
public static void printName() {
System.out.println(name); // ERROR -- which student's name?
System.out.println(this.name); // ERROR -- no 'this' in static context
}
// This WILL compile:
public static int getCount() {
return count; // OK -- count is static too
}
}
class Student():
count = 0 # class attribute (shared)
# This FAILS when called as Student.print_name():
# without self there is no way to reach any one student's name
def print_name():
print(name) # ERROR - which student's name?
# This works:
def get_count():
return Student.count # OK - count belongs to the class
“Non-static variable cannot be referenced from a static context” (static method ထဲကနေ non-static variable ကို သုံးလို့ မရပါ) ဆိုတာ Java စလေ့လာသူတွေ အတွေ့ရအများဆုံး compiler (code တစ်ခုလုံးကို ကြိုတင် ဘာသာပြန်တဲ့ program) error တွေထဲက တစ်ခုပါ။ Static method ထဲမှာ instance variable ကို သုံးဖို့ ကြိုးစားနေတယ်လို့ ဆိုလိုပါတယ်။ Method ကို non-static လုပ်ပါ၊ ဒါမှမဟုတ် object ကို parameter (method ကို ပေးလိုက်တဲ့ တန်ဖိုးကို လက်ခံတဲ့ variable) အဖြစ် ပေးပို့ပါ။
Static Constants (ပြောင်းလို့ မရတဲ့ static တန်ဖိုးများ)
Static variable တွေကို final နဲ့ တွဲလိုက်ရင် constant (ပြောင်းလို့ မရတဲ့ တန်ဖိုး) တွေ ဖြစ်လာပါတယ်: object အားလုံး မျှသုံးပြီး ဘယ်တော့မှ ပြောင်းလို့ မရတဲ့ တန်ဖိုးတွေပါ:
public class Circle {
public static final double PI = 3.14159265358979;
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getArea() {
return PI * radius * radius;
}
}
class Circle():
PI = 3.14159265358979 # class attribute; Python has no final keyword -
# the ALL-CAPS name marks it as a constant by convention
def __init__(self, radius):
self._radius = radius
def get_area(self):
return Circle.PI * self._radius * self._radius
System.out.println(Circle.PI); // 3.14159265358979
// Circle.PI = 3.0; // ERROR -- final cannot be reassigned
print(Circle.PI) # 3.14159265358979
# Circle.PI = 3.0 # would actually run - Python does not enforce constants;
# # the ALL-CAPS name is a "do not change" signal
PI က ဖတ်လို့ ဘာမှ မထိခိုက်လို့ (ဘယ်တော့မှ မပြောင်းလို့) public ဖြစ်ပါတယ်၊ စက်ဝိုင်း (circle) အားလုံးအတွက် တူညီလို့ static ဖြစ်ပါတယ်၊ တန်ဖိုး ပုံသေ ဖြစ်လို့ final ဖြစ်ပါတယ်။
Static ကို ဘယ်အချိန်မှာ သုံးမလဲ
| ဒီလို အခြေအနေမှာ static ကို သုံးပါ… | ဥပမာ |
|---|---|
| ဒေတာကို object အားလုံး မျှသုံးတဲ့အခါ | ဖန်တီးပြီးသား object တွေရဲ့ count |
| Method က ဘယ် object ရဲ့ ဒေတာမှ မလိုတဲ့အခါ | Math.sqrt(), Integer.parseInt() |
| တန်ဖိုးက constant ဖြစ်တဲ့အခါ | Circle.PI, Integer.MAX_VALUE |
| Method က သူ့ parameter တွေပေါ်မှာပဲ အလုပ်လုပ်တဲ့ utility/helper (အထွေထွေ အကူ) method ဖြစ်တဲ့အခါ | MathHelper.square(n) |
| ဒီလို အခြေအနေမှာ static ကို မသုံးပါနဲ့… | ဥပမာ |
|---|---|
| Object တစ်ခုစီမှာ ကိုယ်ပိုင် copy လိုတဲ့အခါ | name, item, grade |
| Method က instance ဒေတာကို ဖတ်တာ ဒါမှမဟုတ် ပြောင်းတာ လုပ်တဲ့အခါ | getItem(), getOrderId() |
Method က this ကို သုံးတဲ့အခါ | လက်ရှိ object ကို ညွှန်းတဲ့ ဘယ် method မဆို |
အဆင့်ဆင့် ရှင်းပြထားတဲ့ ဥပမာများ
ဥပမာ 1: Object အရေအတွက်ကို မှတ်ထားခြင်း
public class Order {
private static int nextId = 1; // shared counter
private int orderId; // unique per object
private String item;
public Order(String item) {
this.orderId = nextId; // assign current counter value
nextId++; // increment for next order
this.item = item;
}
public int getOrderId() { return orderId; }
public String getItem() { return item; }
public static int getNextId() { return nextId; }
}
class Order():
next_id = 1 # class attribute - the shared counter
def __init__(self, item):
self._order_id = Order.next_id # unique per object
Order.next_id = Order.next_id + 1 # increment for the next order
self._item = item
def get_order_id(self):
return self._order_id
def get_item(self):
return self._item
def get_next_id(): # no self - belongs to the class
return Order.next_id
Order o1 = new Order("Laptop");
Order o2 = new Order("Mouse");
Order o3 = new Order("Keyboard");
System.out.println(o1.getOrderId()); // 1
System.out.println(o2.getOrderId()); // 2
System.out.println(o3.getOrderId()); // 3
System.out.println(Order.getNextId()); // 4 (next available)
o1 = Order("Laptop")
o2 = Order("Mouse")
o3 = Order("Keyboard")
print(o1.get_order_id()) # 1
print(o2.get_order_id()) # 2
print(o3.get_order_id()) # 3
print(Order.get_next_id()) # 4 (next available)
Order (မှာယူမှု) တစ်ခုစီက မျှသုံးတဲ့ counter ကနေ မထပ်တဲ့ ID တစ်ခုစီ ရပါတယ်။ Counter က order တစ်ခုချင်းစီမှာ မဟုတ်ဘဲ class မှာ ရှိပါတယ်။
ဥပမာ 2: Static utility method (အထွေထွေ အသုံးဝင်တဲ့ static method)
public class StringHelper {
public static String reverse(String text) {
String result = "";
for (int i = text.length() - 1; i >= 0; i--) {
result = result + text.charAt(i);
}
return result;
}
public static boolean isPalindrome(String text) {
String lower = text.toLowerCase();
return lower.equals(reverse(lower));
}
}
class StringHelper():
def reverse(text): # no self - operates only on its parameter
result = ""
for i in range(len(text) - 1, -1, -1): # counts down from the last index to 0
result = result + text[i]
return result
def is_palindrome(text):
lower = text.lower()
return lower == StringHelper.reverse(lower) # == compares content in Python
System.out.println(StringHelper.reverse("hello")); // olleh
System.out.println(StringHelper.isPalindrome("racecar")); // true
System.out.println(StringHelper.isPalindrome("hello")); // false
print(StringHelper.reverse("hello")) # olleh
print(StringHelper.is_palindrome("racecar")) # True (Java prints true)
print(StringHelper.is_palindrome("hello")) # False
StringHelper object တစ်ခုမှ ဘယ်တော့မှ မဖန်တီးပါဘူး။ Method တွေက သူတို့ရဲ့ parameter တွေပေါ်မှာပဲ အလုပ်လုပ်လို့ class ပေါ်မှာ တိုက်ရိုက် ခေါ်ပါတယ်: ဘယ် object ရဲ့ state (object ထဲမှာ လက်ရှိ ရှိနေတဲ့ တန်ဖိုးများ) မှ မလိုပါဘူး။
Quick Check (အမြန် စစ်ဆေးမေးခွန်း)
Q1. Static variable ရဲ့ copy ဘယ်နှစ်ခု ရှိသလဲ။
Q2. Static method က instance variable တွေကို (object reference မပါဘဲ) တိုက်ရိုက် ဘာကြောင့် မသုံးနိုင်တာလဲ။
Q3. main ကို ဘာကြောင့် static လို့ ကြေညာသလဲ။
Q4. Static method ကို ခေါ်ဖို့ အကြံပြုထားတဲ့ နည်းက ဘယ်ဟာလဲ။
Q5. Order class ထဲမှာ ဒီအရာတွေထဲက ဘယ်ဟာက static မဖြစ်သင့်သလဲ။
Trace Exercise (code ကို တစ်ဆင့်ချင်း လိုက်ကြည့်ခြင်း)
ဥပမာ 1 က Order class ကို trace (တစ်ဆင့်ချင်း လိုက်ပြီး မှတ်) လုပ်ပါ။ Static nextId ရော object တစ်ခုစီရဲ့ instance orderId ပါ လိုက်မှတ်ပါ။
Trace: Static နဲ့ Instance
Order o1 = new Order("Laptop");
Order o2 = new Order("Mouse");
Order o3 = new Order("Keyboard");| ဘယ် line ပြီးနောက် | nextId (static) | o1.orderId | o2.orderId | o3.orderId |
|---|---|---|---|---|
| Object မဖန်တီးခင် | 1 | -- | -- | -- |
| o1 = new Order("Laptop") ပြီးနောက် | -- | -- | ||
| o2 = new Order("Mouse") ပြီးနောက် | -- | |||
| o3 = new Order("Keyboard") ပြီးနောက် |
သတိထားကြည့်ပါ: constructor (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method) run တိုင်း
nextIdပြောင်းပါတယ် (မျှသုံးတာမို့လို့ပါ)။orderIdတစ်ခုစီကိုတော့ object ဖန်တီးချိန်မှာ တစ်ကြိမ်ပဲ သတ်မှတ်ပြီး ဘယ်တော့မှ မပြောင်းပါဘူး (instance မို့လို့ပါ)။ ဒါက static နဲ့ instance ကြားက အခြေခံ ကွာခြားချက်ပါ။
Spot the Error (အမှား ရှာခြင်း)
ဒီ code က compile မဖြစ်ပါဘူး။ Error ပါတဲ့ line ကို ရွေးပါ၊ ပြီးရင် ပြင်နည်းကို ရွေးပါ။
မှန်ကန်တဲ့ ပြင်နည်းကို ရွေးပါ:
Predict the Output (output ကို ကြိုခန့်မှန်းခြင်း)
ဒီ code က ဘာကို print ထုတ်မလဲ။
Student s1 = new Student("Alice");
Student s2 = new Student("Bob");
Student s3 = new Student("Charlie");
System.out.println(Student.getCount()); o1.getOrderId() က ဘာကို print ထုတ်မလဲ။
Order o1 = new Order("Laptop");
Order o2 = new Order("Mouse");
System.out.println(o1.getOrderId()); အပေါ်က order နှစ်ခုလုံးကို ဖန်တီးပြီးတဲ့အခါ Order.getNextId() က ဘာကို print ထုတ်မလဲ။
Order o1 = new Order("Laptop");
Order o2 = new Order("Mouse");
System.out.println(Order.getNextId()); Practice Exercises (လေ့ကျင့်ခန်းများ)
Core (အခြေခံ အဆင့်)
- Static လား instance လား: အောက်ပါ တစ်ခုစီက static ဖြစ်သင့်လား instance ဖြစ်သင့်လား ဖော်ပြပြီး ဘာကြောင့်လဲ ရှင်းပြပါ:
Carတစ်စီးရဲ့speed- ဖန်တီးပြီးသား
Carobject စုစုပေါင်းအတွက် counter - ကား တစ်စီးရဲ့ လက်ရှိ speed ကို ပြန်ပေးတဲ့
getSpeed()method - ကား ဘယ်နှစ်စီး ရှိလဲ ပြန်ပေးတဲ့
getTotalCars()method MAX_SPEED = 200ဆိုတဲ့ constant
- Counter ထည့်ခြင်း: Encapsulation စာမျက်နှာက
Productclass ကို ယူပါ။ Product ဘယ်နှစ်ခု ဖန်တီးပြီးပြီလဲ မှတ်ထားတဲ့ statictotalProductsvariable နဲ့ staticgetTotalProducts()method ကို ထည့်ပါ။ Product အများအပြား ဖန်တီးပြီး စမ်းသပ်ပါ။
Extension (တိုးချဲ့ အဆင့်)
-
အလိုအလျောက် တိုးသွားတဲ့ ID: Ticket (လက်မှတ်) တစ်ခုစီက မထပ်တဲ့ ID (1001 ကနေ စ) ကို အလိုအလျောက် ရတဲ့
Ticketclass တစ်ခုကို ဖန်တီးပါ။ Static counter ကို သုံးပါ။getTicketId()(instance) နဲ့getNextTicketId()(static) ကို ထည့်ပါ။ -
Utility class (static method တွေပဲ ပါတဲ့ အကူ class): Static method တွေပဲ ပါတဲ့
Validatorclass တစ်ခုကို ဖန်တီးပါ:isPositive(int n),isInRange(int n, int min, int max),isNonEmpty(String s)။ Constructor မလိုသင့်ပါဘူး: ဘာကြောင့်လဲ ရှင်းပြပါ။
Challenge (စိန်ခေါ်မှု အဆင့်)
- Design ကို ခွဲခြမ်းစိတ်ဖြာခြင်း: သင့်အဖွဲ့က chat application တစ်ခု တည်ဆောက်နေပါတယ်။ အောက်ပါ တစ်ခုစီက static ဖြစ်သင့်လား instance ဖြစ်သင့်လား ဆုံးဖြတ်ပြီး အကြောင်းပြချက် ပေးပါ:
Message.content(message တစ်ခုရဲ့ စာသား)Message.totalMessagesSent(user အားလုံးဆီကနေ ပို့ပြီးသား message စုစုပေါင်း)User.usernameUser.onlineCount(လက်ရှိ online ဖြစ်နေတဲ့ user အရေအတွက်)ChatRoom.sendMessage(Message m)(room ထဲက user အားလုံးဆီ ပို့ပါတယ်)
ဆက်စပ် ခေါင်းစဉ်များ
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Access Modifiers (ဘယ်ကနေ သုံးခွင့်ရလဲ သတ်မှတ်တဲ့ keyword များ):
staticကို access modifier တွေနဲ့ မကြာခဏ ရောထွေးတတ်ပေမယ့် ရည်ရွယ်ချက် မတူပါဘူး - အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Classes and Objects: static ဆိုတာ ဘာလဲ မလေ့လာခင် instance variable တွေကို နားလည်ထားဖို့
- နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: Object References။ Reference တွေ အလုပ်လုပ်ပုံ၊ aliasing (variable နှစ်ခုက object တစ်ခုတည်းကို ညွှန်းခြင်း)၊
null၊==နဲ့.equals()ကွာခြားချက် - ဆက်စပ် ခေါင်းစဉ်: Encapsulation (ဒေတာနဲ့ method ကို တစ်စုတည်း ထုပ်ပိုးခြင်း): static member တွေကလည်း
private/publicစည်းမျဉ်း တူတူကို လိုက်နာပါတယ်