Java Reflection: Classes, Methods, Fields runtime දී වෙනස් කරමු - SC Guide

අනේ මචන්ලා, කොහොමද ඉතින් ඔයාලට? අද අපි කතා කරන්න යන්නේ Java වල පොඩ්ඩක් "ගැඹුරු" කියල හිතෙන, ඒත් ගොඩක්ම පවර්ෆුල් වෙන topic එකක් ගැන. ඒ තමයි Java Reflection.
Java Reflection: ඔබ නොදත් බලය
හරි, දැන් ඔයාලා හිතනවා ඇති මේ Reflection කියන්නේ මොකක්ද කියලා? සරලවම කිව්වොත්, සාමාන්යයෙන් අපේ Java program එකක් compile කරලා run වෙනකොට, අපි දන්නවා මොන class එකද, මොන method එකද, මොන field එකද use වෙන්නේ කියලා. ඒත් මේ Reflection කියන ටූල් එකෙන් අපිට පුළුවන් program එක run වෙන වෙලාවෙදී (runtime) class එකක් ගැන තොරතුරු දැනගන්න, ඒ වගේම ඒ class එකේ methods call කරන්න, fields වලට values දෙන්න, ඒ වගේම අලුත් objects හදන්නත් පුළුවන්. හිතන්නකෝ, අපිට Class එකේ නම String එකක් විදියට දීලා, ඒ Class එකේ object එකක් හදන්න පුළුවන් කියලා! මාර වැඩක් නේද?
මේක අර අරම “අමුතු” වගේ පෙනුනත්, ඇත්තටම අපේ දිනපතාම පාවිච්චි කරන ගොඩක් frameworks සහ tools මේ Reflection මත තමයි වැඩ කරන්නේ. උදාහරණයක් විදියට Spring, Hibernate, JUnit වගේ ඒවා.
Reflection කියන්නේ මොකක්ද හරියටම?
Java Reflection කියන්නේ Java API එකේ කොටසක්. ඒක තියෙන්නේ java.lang.reflect
package එක ඇතුලේ. මේක අපිට ඉඩ දෙනවා runtime එකේදී classes, interfaces, fields, methods, constructors වගේ දේවල් inspect කරන්න, ඒ වගේම modify කරන්නත්. සාමාන්යයෙන් අපිට compile time එකේදී Class එකක් ගැන හැම විස්තරයක්ම දැනගන්න පුළුවන්. ඒත් Reflection අපිට උදව් කරනවා, compile time එකේදී නොදන්නා class එකක් ගැන runtime එකේදී විස්තර දැනගෙන වැඩ කරන්න. මේකෙන් අපිට dynamic applications හදන්න පුළුවන්.
ප්රධානම Reflection Classes
Reflection එක්ක වැඩ කරනකොට අපිට හමුවෙන ප්රධාන Class කීපයක් තියෙනවා:
java.lang.Class
: මේක තමයි Reflection වලට පදනම. ඕනෑම object එකක runtime class එක නියෝජනය කරන්නේ මේ Class object එකකින්. මේකෙන් අපිට පුළුවන් class එකක methods, fields, constructors වගේ දේවල් ගැන විස්තර දැනගන්න.java.lang.reflect.Method
: Class එකක method එකක් නියෝජනය කරනවා. මේකෙන් අපිට පුළුවන් methods invoke කරන්න.java.lang.reflect.Field
: Class එකක field (instance variable) එකක් නියෝජනය කරනවා. මේකෙන් අපිට පුළුවන් field එකක value එක ගන්න, නැත්නම් set කරන්න.java.lang.reflect.Constructor
: Class එකක constructor එකක් නියෝජනය කරනවා. මේකෙන් අපිට පුළුවන් dynamic විදියට objects හදන්න.
ප්රායෝගික උදාහරණයක් බලමුද?
හරි, අපි බලමු මේවා කොහොමද වැඩ කරන්නේ කියලා. අපි හිතමු අපිට Student
කියලා Class එකක් තියෙනවා කියලා:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void secretMethod() {
System.out.println("This is a secret message!");
}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
}
1. Class Object එකක් ලබාගැනීම
ඕනෑම Class එකක Class
object එකක් ලබාගන්න විවිධ ක්රම තියෙනවා:
// 1. Class.forName() භාවිතා කරලා (බහුලව භාවිතා වන ක්රමය)
try {
Class<?> studentClass = Class.forName("Student"); // Package name එකත් එක්ක දෙන්න ඕනේ
System.out.println("Class Name: " + studentClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 2. object එකක .getClass() method එක භාවිතා කරලා
Student s = new Student("Nimal", 20);
Class<?> studentClassFromObject = s.getClass();
System.out.println("Class Name (from object): " + studentClassFromObject.getName());
// 3. .class literal එක භාවිතා කරලා (compile time එකේදී class එක දන්නවනම්)
Class<Student> studentClassLiteral = Student.class;
System.out.println("Class Name (from literal): " + studentClassLiteral.getName());
2. Methods සහ Fields Inspect කිරීම
Class එකක තියෙන methods සහ fields මොනවද කියලා බලමු:
try {
Class<?> studentClass = Class.forName("Student");
// සියලු public methods ලබාගැනීම
Method[] methods = studentClass.getMethods();
System.out.println("\n--- Public Methods ---");
for (Method method : methods) {
System.out.println(method.getName());
}
// Class එකේ declare කරපු සියලු methods ලබාගැනීම (public, private, protected)
Method[] declaredMethods = studentClass.getDeclaredMethods();
System.out.println("\n--- Declared Methods ---");
for (Method method : declaredMethods) {
System.out.println(method.getName());
}
// සියලු public fields ලබාගැනීම
Field[] fields = studentClass.getFields();
System.out.println("\n--- Public Fields ---");
for (Field field : fields) {
System.out.println(field.getName());
}
// Class එකේ declare කරපු සියලු fields ලබාගැනීම (public, private, protected)
Field[] declaredFields = studentClass.getDeclaredFields();
System.out.println("\n--- Declared Fields ---");
for (Field field : declaredFields) {
System.out.println(field.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
මේකෙන් ඔයාලට පේනවා ඇති getMethods()
සහ getFields()
කියන ඒවා public
ඒවා විතරක් පෙන්නනවා. ඒත් getDeclaredMethods()
සහ getDeclaredFields()
කියන ඒවා private
වුණත් පෙන්නනවා. මේක තමයි Reflection වල තියෙන සුපිරිම power එක!
3. Methods Invoke කිරීම (Call කිරීම)
අපිට runtime එකේදී method එකක් call කරන්න පුළුවන්. ඒ වගේම private methods වුණත්!
try {
Class<?> studentClass = Class.forName("Student");
Object studentObj = studentClass.getDeclaredConstructor(String.class, int.class).newInstance("Kamal", 25); // Object එකක් හදමු
// public method එකක් call කිරීම
Method getNameMethod = studentClass.getMethod("getName");
String name = (String) getNameMethod.invoke(studentObj);
System.out.println("\nStudent Name (using Reflection): " + name);
// private method එකක් call කිරීම
Method secretMethod = studentClass.getDeclaredMethod("secretMethod");
secretMethod.setAccessible(true); // Private methods වලට access කරන්න මේක True කරන්න ඕනේ
secretMethod.invoke(studentObj);
} catch (Exception e) {
e.printStackTrace();
}
4. Fields වල Values වෙනස් කිරීම
ඒ වගේම අපිට private fields වල values වුණත් වෙනස් කරන්න පුළුවන්:
try {
Class<?> studentClass = Class.forName("Student");
Object studentObj = studentClass.getDeclaredConstructor(String.class, int.class).newInstance("Sunil", 30);
// මුලින් value එක බලමු
System.out.println("\nOriginal Student: " + studentObj);
// private field එකක් වෙනස් කිරීම
Field nameField = studentClass.getDeclaredField("name");
nameField.setAccessible(true); // private field එකට access කරන්න මේක True කරන්න ඕනේ
nameField.set(studentObj, "Saman"); // Value එක set කරමු
Field ageField = studentClass.getDeclaredField("age");
ageField.setAccessible(true);
ageField.setInt(studentObj, 35); // int type එකට int value එකක් set කරමු
// වෙනස් කරපු value එක බලමු
System.out.println("Modified Student: " + studentObj);
} catch (Exception e) {
e.printStackTrace();
}
Java Reflection වල වාසි සහ අවාසි
වාසි (Advantages)
- Dynamic Behavior: Compile time එකේදී නොදන්නා class, method, field වලට runtime එකේදී access කරලා වැඩ කරන්න පුළුවන්. මේක Frameworks, IDEs, Debuggers වගේ දේවල් වලට ගොඩක් වැදගත්.
- Extensibility: අපේ code එකට අලුත් features එකතු කරන්න පුළුවන්, කලින් compile කරපු code එක වෙනස් නොකර.
- Testing & Debugging: JUnit වගේ testing frameworks, debugging tools Reflection පාවිච්චි කරනවා private methods test කරන්න.
- Framework Development: Spring (Dependency Injection), Hibernate (ORM), Jackson (JSON Serialization/Deserialization) වගේ frameworks Reflection වලින් තමයි වැඩ කරන්නේ.
අවාසි (Disadvantages)
- Performance Overhead: Reflection සාමාන්ය method calls වලට වඩා සෑහෙන්න හෙමින් වැඩ කරන්නේ. මොකද මේකට security checks, type checking වගේ දේවල් runtime එකේදී කරන්න වෙනවා.
- Security Issues:
setAccessible(true)
භාවිතා කරලා private methods/fields වලට access කරනකොට, Java security model එක bypass වෙනවා. ඒ නිසා ප්රවේසමෙන් පාවිච්චි කරන්න ඕනේ. - Code Complexity: Reflection code සාමාන්ය code වලට වඩා කියවන්න සහ maintain කරන්න අමාරුයි. Compile time type checking නැති නිසා bugs අහු වෙනවා අඩුයි, runtime එකේදී තමයි ඒවා මතුවෙන්නේ.
- Breaking Encapsulation: Object-Oriented Programming (OOP) වල ප්රධානම සංකල්පයක් වන encapsulation එක Reflection වලින් කැඩෙනවා.
අවසාන වශයෙන්...
කොහොමද ඉතින් යාළුවනේ, මේ Java Reflection කියන දේ ගැන යම්කිසි අවබෝධයක් ලැබෙන්න ඇති කියලා හිතනවා. මේක ටිකක් advanced topic එකක් වුණත්, මේක තේරුම් ගන්න එකෙන් ඔයාට Java frameworks වැඩ කරන විදිය වගේම, තමන්ගේම dynamic applications හදනකොට ගොඩක් උදව්වක් වෙයි. හැබැයි අර කියපු අවාසිත් මතක තියාගෙන, ඕනෙම නැති තැනක Reflection පාවිච්චි නොකර ඉන්නත් මතක තියාගන්න. හැම දේටම Reflection ඕනේ නෑ!
දැන් ඔයාට පුළුවන් මේ උදාහරණ code ටික ඔයාගේ IDE එකේ run කරලා බලන්න. මොනවා හරි ප්රශ්න තියෙනවා නම්, comment section එකේ අහන්න අමතක කරන්න එපා. අපි ලබන post එකෙන් තවත් සුපිරි topic එකකින් හමුවෙමු! Java එක්ක දිගටම code කරමු!