The this Keyword (လက်ရှိ object ကို ညွှန်းတဲ့ this keyword)
B3.1: Use the this keyword to refer to the current object.
မြန်မာလို: လက်ရှိ object (class တစ်ခုကနေ ဖန်တီးထားတဲ့ instance) ကို ညွှန်းဖို့ this keyword (programming language မှာ အထူး အဓိပ္ပာယ်ရှိတဲ့ စကားလုံး) ကို သုံးနိုင်ရပါမယ်။
အဓိက အယူအဆများ
this ဆိုတာ ဘာလဲ
this keyword က current object (လက်ရှိ code run နေတဲ့ object) ကို ညွှန်းတဲ့ reference (object ရှိရာ memory နေရာကို ညွှန်းတဲ့ တန်ဖိုး) ပါ: ဆိုလိုတာက အခု method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း) ဒါမှမဟုတ် constructor (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method) run နေတဲ့ သီးခြား instance ပါ။ Non-static (static မဟုတ်တဲ့) method နဲ့ constructor တိုင်းမှာ code run နေတဲ့ object ကို ညွှန်းထားတဲ့ မမြင်ရတဲ့ this reference တစ်ခု ရှိပါတယ်။ (Python မှာ this နဲ့ တူတာက self ပါ၊ ဒါပေမယ့် မမြင်ရတာ မဟုတ်ပါဘူး: method တိုင်းရဲ့ ပထမ parameter (method ကို ပေးလိုက်တဲ့ တန်ဖိုးကို လက်ခံတဲ့ variable) အဖြစ် self ကို ရေးရပါတယ်။)
this ကို အများဆုံး သုံးတာက method parameter တွေနဲ့ instance variable (object တစ်ခုချင်းရဲ့ ကိုယ်ပိုင် variable) တွေကြား နာမည် တူနေတဲ့ ပြဿနာ ကို ဖြေရှင်းဖို့ပါ။
Parameter Shadowing ပြဿနာ
Constructor ဒါမှမဟုတ် method ရဲ့ parameter က instance variable နဲ့ နာမည် တူနေရင် parameter က instance variable ကို shadow (ဖုံးကွယ်) လုပ်ပါတယ်။ ဒီလို ဖြစ်တာကို parameter shadowing (နာမည်တူ parameter က instance variable ကို ဖုံးထားခြင်း) လို့ ခေါ်ပါတယ်။ this မပါရင် compiler (code တစ်ခုလုံးကို ကြိုတင် ဘာသာပြန်တဲ့ program) က assignment (variable ထဲ တန်ဖိုး ထည့်ခြင်း) ရဲ့ နှစ်ဘက်လုံးအတွက် အနီးဆုံး scope (variable ကို သုံးလို့ရတဲ့ နယ်ပယ်)၊ ဆိုလိုတာက parameter ကို သုံးပါတယ်။
public class Pet {
private String name;
public Pet(String name) {
name = name; // BUG: assigns the parameter to itself
// the instance variable stays null
}
public String getName() { return name; }
}
class Pet():
def __init__(self, name):
name = name # BUG: assigns the parameter to itself
# the attribute self._name is never created
def get_name(self):
return self._name
Comment တွေက name = name က parameter ကို သူ့ကိုယ်သူ ပြန်ထည့်တာ ဖြစ်လို့ bug (code ထဲက အမှား) ဖြစ်တယ်လို့ ပြောပါတယ်: Java မှာ instance variable က null (ဘာ object ကိုမှ မညွှန်းတဲ့ တန်ဖိုး) ဖြစ်နေဆဲပါ၊ Python မှာ self._name attribute ကို ဘယ်တော့မှ မဖန်တီးပါဘူး။
Pet p = new Pet("Max");
System.out.println(p.getName()); // null -- the instance variable was never set!
p = Pet("Max")
print(p.get_name()) # error - the attribute was never created
# (Java gives null here; Python raises an AttributeError)
Java မှာ instance variable ကို တန်ဖိုး တစ်ခါမှ မထည့်ခဲ့လို့ null ကို print ထုတ်ပါတယ်။ Python မှာတော့ attribute ကို မဖန်တီးခဲ့လို့ AttributeError (object မှာ မရှိတဲ့ attribute ကို ယူလို့ ဖြစ်တဲ့ error) ကို raise (exception ဖြစ်ကြောင်း အချက်ပြ) လုပ်ပါတယ်။
name = name ဆိုတဲ့ line က parameter name ကို သူ့ကိုယ်သူ ပြန်ထည့်ပါတယ်။ Instance variable this.name ကို ဘယ်တော့မှ မထိတော့လို့ null အဖြစ်ပဲ ကျန်နေပါတယ်။
ဖြေရှင်းနည်း: this.variable
this.name လို့ ရေးရင် instance variable ကို တိတိကျကျ ညွှန်းပြီး ဘာမှ မတွဲထားတဲ့ name က parameter ကို ညွှန်းပါတယ်:
public class Pet {
private String name;
public Pet(String name) {
this.name = name; // this.name = instance variable
// name = parameter
}
public String getName() { return name; }
}
class Pet():
def __init__(self, name):
self._name = name # self._name = the object's attribute
# name = the parameter
def get_name(self):
return self._name
Pet p = new Pet("Max");
System.out.println(p.getName()); // Max -- works correctly
p = Pet("Max")
print(p.get_name()) # Max - works correctly
this.nameက instance variable ကို အမြဲ ညွှန်းပါတယ်။ ဘာမှ မတွဲထားတဲ့nameက အနီးဆုံး scope ကို ညွှန်းပါတယ်:nameparameter ပါတဲ့ constructor ဒါမှမဟုတ် method ထဲမှာဆိုရင် parameter ကို ဆိုလိုပါတယ်။ အဲဒီလို နေရာ မဟုတ်ရင်တော့ ဘာမှ မတွဲထားတဲ့nameနဲ့this.nameက အတူတူပါပဲ။
this ကို မဖြစ်မနေ သုံးရမယ့် အခါ
Parameter နာမည်က instance variable နာမည်နဲ့ တူတဲ့အခါ this ကို မဖြစ်မနေ သုံးရပါတယ်။ မသုံးရင် assignment က အသုံးဝင်တာ ဘာမှ မလုပ်ပါဘူး။
public void setAge(int age) {
this.age = age; // required -- parameter shadows instance variable
}
def set_age(self, age):
self._age = age # self. is ALWAYS required in Python - the attribute
# and the parameter never clash
Python မှာ self. ကို အမြဲ ရေးရလို့ attribute နဲ့ parameter က ဘယ်တော့မှ နာမည် မတိုက်ပါဘူး။
this ကို မသုံးလည်း ရတဲ့ အခါ
နာမည် တူနေတာ မရှိရင် this ကို သုံးချင်မှ သုံးပါ။ အောက်က ပုံစံ နှစ်ခုလုံး အတူတူပါပဲ:
public double getArea() {
return this.width * this.height; // explicit -- works
}
public double getArea() {
return width * height; // implicit -- also works (no shadowing)
}
def get_area(self):
return self._width * self._height # Python has no "implicit" form -
# attributes are always reached through self
this ကို ထည့်ရေးတဲ့ explicit (ထင်ရှားအောင် ရေးတဲ့) ပုံစံရော မထည့်ဘဲ ရေးတဲ့ implicit (ချန်ထားတဲ့) ပုံစံပါ အလုပ်လုပ်ပါတယ်၊ shadowing မရှိလို့ပါ။ Python မှာ implicit ပုံစံ မရှိပါဘူး: attribute တွေကို self ကနေတဆင့်ပဲ အမြဲ ယူသုံးရပါတယ်။
Programmer တော်တော်များများက မသုံးလည်း ရတဲ့ နေရာတွေမှာတောင် ရှင်းလင်းအောင် this ကို အမြဲ သုံးကြပါတယ်။ တချို့ကတော့ လိုတဲ့အခါမှပဲ သုံးပါတယ်။ ပုံစံ နှစ်မျိုးလုံးကို လက်ခံပါတယ်။ (Python မှာ self ကို ဘယ်တော့မှ ချန်လို့ မရပါဘူး: ပုံစံ တစ်မျိုးပဲ ရှိပါတယ်။)
Setter တွေမှာ this ကို သုံးခြင်း
Setter (private attribute ရဲ့ တန်ဖိုးကို ပြောင်းတဲ့ method) တွေမှာ သူတို့ ပြောင်းမယ့် attribute (object ရဲ့ ဒေတာကို သိမ်းတဲ့ variable) နဲ့ နာမည်တူ parameter တစ်ခု အမြဲလိုလို ပါပါတယ်:
public class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius; // no conflict, this is optional
}
public void setRadius(double radius) {
if (radius > 0) {
this.radius = radius; // required -- parameter shadows field
}
}
public double getArea() {
return Math.PI * radius * radius;
}
}
import math
class Circle():
def __init__(self, radius):
self._radius = radius
def get_radius(self):
return self._radius
def set_radius(self, radius):
if radius > 0:
self._radius = radius # self. keeps the attribute and the parameter apart
def get_area(self):
return math.pi * self._radius * self._radius
getRadius() မှာ နာမည် မတိုက်လို့ this မလိုပါဘူး။ setRadius() မှာတော့ parameter က field (object ထဲက အချက်အလက် အကွက်) ကို shadow လုပ်လို့ this ကို မဖြစ်မနေ သုံးရပါတယ်။ Python မှာ self. က attribute နဲ့ parameter ကို ခွဲထားပေးပါတယ်။
ပြဿနာကို လုံးဝ ရှောင်ခြင်း
တချို့ programmer တွေက parameter တွေကို မတူတဲ့ နာမည်တွေ ပေးပြီး shadowing ကို ရှောင်ကြပါတယ်:
public Pet(String petName) {
name = petName; // no conflict, no this needed
}
def __init__(self, pet_name):
self._name = pet_name # a different parameter name works in Python too,
# but self. is still required either way
နာမည် မတိုက်လို့ this မလိုပါဘူး။ Python မှာလည်း မတူတဲ့ parameter နာမည် သုံးလို့ ရပေမယ့် self. ကိုတော့ ရေးရဆဲပါ။
ဒီနည်းက အလုပ်ဖြစ်ပါတယ်၊ ဒါပေမယ့် Java မှာ ပုံမှန် ရေးလေ့ရှိတဲ့ ပုံစံက နာမည်တူတွေကို this နဲ့ တွဲသုံးတာပါ:
public Pet(String name) {
this.name = name; // standard Java convention
}
def __init__(self, name):
self._name = name # standard Python convention - self must be the
# first parameter of every method
Python ရဲ့ ပုံမှန် ရေးထုံးမှာ self က method တိုင်းရဲ့ ပထမ parameter ဖြစ်ရပါမယ်။
this နည်းက textbook တွေမှာရော Java code အများစုမှာပါ ပုံမှန် သုံးတဲ့ ပုံစံပါ။
အဆင့်ဆင့် ရှင်းပြထားတဲ့ ဥပမာများ
ဥပမာ 1: this ပါတာနဲ့ မပါတာကို Trace လုပ်ခြင်း
this ပါရင်:
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x; // instance variable = parameter
this.y = y;
}
}
Point p = new Point(3, 7);
// p.x = 3, p.y = 7 ✓
class Point():
def __init__(self, x, y):
self._x = x # attribute = parameter
self._y = y
p = Point(3, 7)
# p's _x is 3, _y is 7 ✓
this မပါရင်:
public class Point {
private int x;
private int y;
public Point(int x, int y) {
x = x; // parameter = parameter (no effect on instance variable)
y = y;
}
}
Point p = new Point(3, 7);
// p.x = 0, p.y = 0 ✗ (instance variables keep default int value)
class Point():
def __init__(self, x, y):
x = x # parameter = parameter (no attribute is ever created)
y = y
p = Point(3, 7)
# p has NO _x or _y attributes at all - reading them raises an error ✗
# (Java's instance variables would still exist, holding the default 0)
this ပါရင် p.x က 3 နဲ့ p.y က 7 ဖြစ်ပါတယ်။ this မပါရင် x = x က parameter ကို parameter ထဲ ပြန်ထည့်ရုံပဲ ဖြစ်လို့ instance variable တွေကို မထိပါဘူး: Java မှာ p.x နဲ့ p.y က int ရဲ့ default value (သတ်မှတ်မထားရင် သုံးတဲ့ တန်ဖိုး) 0 အဖြစ် ကျန်နေပါတယ်။ Python မှာတော့ _x၊ _y attribute တွေကို လုံးဝ မဖန်တီးလို့ ဖတ်ရင် error ဖြစ်ပါတယ်။
ဥပမာ 2: this ကို တစ်လျှောက်လုံး သုံးထားတဲ့ Class အပြည့်အစုံ
public class Employee {
private String name;
private double salary;
private String department;
public Employee(String name, double salary, String department) {
this.name = name;
this.salary = salary;
this.department = department;
}
public String getName() { return name; }
public double getSalary() { return salary; }
public String getDepartment() { return department; }
public void setSalary(double salary) {
if (salary >= 0) {
this.salary = salary;
}
}
public void raiseSalary(double percentage) {
// no conflict here -- percentage is not an instance variable name
salary = salary * (1 + percentage / 100.0);
}
}
class Employee():
def __init__(self, name, salary, department):
self._name = name
self._salary = salary
self._department = department
def get_name(self):
return self._name
def get_salary(self):
return self._salary
def get_department(self):
return self._department
def set_salary(self, salary):
if salary >= 0:
self._salary = salary
def raise_salary(self, percentage):
# self. is required here too - Python never lets you drop it
self._salary = self._salary * (1 + percentage / 100.0)
သတိပြုပါ: percentage က ဘယ် instance variable ကိုမှ shadow မလုပ်လို့ raiseSalary မှာ this မလိုပါဘူး။ Parameter salary က field salary ကို shadow လုပ်လို့ setSalary မှာတော့ this လိုပါတယ်။ (Python ဗားရှင်းမှာ method နှစ်ခုလုံးမှာ self. လိုပါတယ်: Python က ဒီလို ခွဲခြားမှု မရှိပါဘူး။)
Quick Check (အမြန် စစ်ဆေးမေးခွန်း)
Q1. Java မှာ this က ဘာကို ညွှန်းသလဲ။
Q2. Constructor မှာ String name parameter ပါပြီး class မှာ private String name field ရှိရင် (this မပါတဲ့) name = name က ဘာလုပ်သလဲ။
Q3. this ကို ဘယ်အချိန်မှာ မဖြစ်မနေ သုံးရသလဲ။
Spot the Error (အမှား ရှာခြင်း)
ဒီ setter က compile ဖြစ်ပေမယ့် ဘာ အကျိုးမှ မရှိပါဘူး: setRadius(5.0) ကို ခေါ်လည်း စက်ဝိုင်းရဲ့ radius (အချင်းဝက်) မပြောင်းပါဘူး။ အမှားပါတဲ့ line ကို ရွေးပါ၊ ပြီးရင် ပြင်နည်းကို ရွေးပါ။
ပြင်နည်းကို ရွေးပါ:
Predict the Output (output ကို ကြိုခန့်မှန်းခြင်း)
ဒီ code က ဘာကို print ထုတ်မလဲ။
public class Pet {
private String name;
public Pet(String name) { this.name = name; }
public String getName() { return name; }
}
Pet p = new Pet("Luna");
System.out.println(p.getName()); ဒီ code က ဘာကို print ထုတ်မလဲ။ (သတိပြုပါ: constructor ထဲမှာ this မပါပါဘူး)
public class Pet {
private String name;
public Pet(String name) { name = name; }
public String getName() { return name; }
}
Pet p = new Pet("Luna");
System.out.println(p.getName()); Practice Exercises (လေ့ကျင့်ခန်းများ)
Core (အခြေခံ အဆင့်)
- Bug ကို ပြင်ပါ: အောက်က constructor မှာ shadowing bug တစ်ခု ပါပါတယ်။ မှန်အောင် ပြန်ရေးပါ:
public class Car { private String make; private int year; public Car(String make, int year) { make = make; year = year; } } thisလိုတဲ့ နေရာကို Identify (ဖြစ်နိုင်တဲ့ အဖြေတွေထဲက ရွေးပြီး ဖော်ပြပါ) လုပ်ပါ: အောက်က class မှာ ဘယ် line တွေမှာthisလိုပြီး ဘယ် line တွေမှာ မလိုလဲ မှတ်ပါ။ ဘာကြောင့်လဲ Explain (ရှင်းပြပါ) လုပ်ပါ။public class Timer { private int seconds; public Timer(int seconds) { seconds = seconds; } public int getSeconds() { return seconds; } public void addTime(int extra) { seconds = seconds + extra; } public void reset(int seconds) { seconds = seconds; } }
Extension (တိုးချဲ့ အဆင့်)
thisပါတဲ့ class အပြည့်အစုံ:title၊directorနဲ့rating(double၊ 0-10) attribute တွေပါတဲ့Movieclass တစ်ခု ရေးပါ။thisကို သုံးတဲ့ parameterised constructor (parameter တွေ လက်ခံတဲ့ constructor) တစ်ခု၊ getter (private attribute ရဲ့ တန်ဖိုးကို ပြန်ပေးတဲ့ method) တွေနဲ့ တန်ဖိုး အပိုင်းအခြားကို validation (တန်ဖိုး မှန်မမှန် စစ်ခြင်း) လုပ်တဲ့setRating(double rating)setter တစ်ခု ရေးပါ။ Parameter နာမည် အားလုံးက attribute နာမည်တွေနဲ့ တူရပါမယ်။
Challenge (စိန်ခေါ်မှု အဆင့်)
- Trace လုပ်ပြီး ရှင်းပြပါ: Class တစ်ခုမှာ ဒီ code ပါပါတယ်:
public class Pair { private int a; private int b; public Pair(int a, int b) { this.a = a; this.b = b; } public void swap() { int temp = a; a = b; b = temp; } }Pair p = new Pair(3, 7); p.swap();ကို Trace (တစ်ဆင့်ချင်း လိုက်ပြီး မှတ်ပါ) လုပ်ပြီးaနဲ့bရဲ့ နောက်ဆုံး တန်ဖိုးတွေကို State (ဖော်ပြပါ) လုပ်ပါ။swap()မှာthisလိုသလား။ ဘာကြောင့် လိုတာလဲ ဒါမှမဟုတ် ဘာကြောင့် မလိုတာလဲ။
ဆက်စပ် ခေါင်းစဉ်များ
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Constructors (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method များ):
thisကို constructor တွေထဲမှာ အသုံးအများဆုံးပါ - အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Classes and Objects (class နဲ့ object များ): instance variable တွေနဲ့ method တွေကို နားလည်ထားဖို့
- နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: Encapsulation (ဒေတာနဲ့ method ကို တစ်စုတည်း ထုပ်ပိုးခြင်း): encapsulation က အားကိုးရတဲ့ getter/setter ပုံစံကို
thisက ဖြစ်နိုင်စေပါတယ် - ဆက်စပ် ခေါင်းစဉ်: Inheritance (parent class ကနေ အမွေဆက်ခံခြင်း): အမွေဆက်ခံထားတဲ့ method တွေထဲမှာတောင်
thisက လက်ရှိ object ကို ညွှန်းပါတယ်၊superကတော့ parent ကို ညွှန်းပါတယ်