হয়তো আপনি সাধারণ জীবনে "প্রতিফলন" ধারণার সম্মুখীন হয়েছেন। এই শব্দটি সাধারণত নিজেকে অধ্যয়নের প্রক্রিয়াকে বোঝায়। প্রোগ্রামিং-এ, এটির একটি অনুরূপ অর্থ রয়েছে - এটি একটি প্রোগ্রাম সম্পর্কে ডেটা বিশ্লেষণ করার একটি প্রক্রিয়া, এমনকি প্রোগ্রামটি চলাকালীন একটি প্রোগ্রামের গঠন এবং আচরণ পরিবর্তন করে।
এখানে গুরুত্বপূর্ণ হল যে আমরা রানটাইমে এটি করছি, কম্পাইল টাইমে নয়। কিন্তু কেন রানটাইমে কোড পরীক্ষা? সর্বোপরি, আপনি ইতিমধ্যে কোডটি পড়তে পারেন :/ প্রতিফলনের ধারণাটি অবিলম্বে পরিষ্কার না হওয়ার একটি কারণ রয়েছে: এই বিন্দু পর্যন্ত, আপনি সর্বদা জানতেন যে আপনি কোন ক্লাসের সাথে কাজ করছেন। উদাহরণস্বরূপ, আপনি একটি
সংক্ষিপ্ততার জন্য, আমরা যথাযথ ব্যতিক্রম হ্যান্ডলিং কোড বাদ দিয়েছি, যা উদাহরণের চেয়ে বেশি জায়গা নেবে। একটি বাস্তব প্রোগ্রামে, অবশ্যই, আপনাকে ভুলভাবে প্রবেশ করা নাম ইত্যাদির সাথে জড়িত পরিস্থিতিগুলি পরিচালনা করা উচিত। ডিফল্ট কনস্ট্রাক্টরটি বেশ সহজ, তাই আপনি দেখতে পাচ্ছেন, ক্লাসের একটি উদাহরণ তৈরি করতে এটি ব্যবহার করা সহজ :) পদ্ধতি ব্যবহার

Cat
ক্লাস লিখতে পারেন:
package learn.codegym;
public class Cat {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void sayMeow() {
System.out.println("Meow!");
}
public void jump() {
System.out.println("Jump!");
}
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;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
আপনি এটি সম্পর্কে সবকিছু জানেন এবং আপনি এটির ক্ষেত্র এবং পদ্ধতিগুলি দেখতে পারেন। ধরুন আপনাকে হঠাৎ প্রোগ্রামে অন্যান্য প্রাণীর ক্লাস চালু করতে হবে। Animal
আপনি সম্ভবত সুবিধার জন্য একটি অভিভাবক শ্রেণীর সাথে একটি ক্লাস উত্তরাধিকার কাঠামো তৈরি করতে পারেন । এর আগে, আমরা এমনকি একটি পশুচিকিত্সা ক্লিনিকের প্রতিনিধিত্বকারী একটি শ্রেণী তৈরি করেছি, যেখানে আমরা একটি Animal
বস্তু (একটি অভিভাবক শ্রেণীর উদাহরণ) পাস করতে পারি এবং প্রোগ্রামটি কুকুর বা বিড়াল কিনা তার উপর ভিত্তি করে প্রাণীটিকে যথাযথভাবে আচরণ করে। যদিও এইগুলি সবচেয়ে সহজ কাজ নয়, প্রোগ্রামটি কম্পাইলের সময় ক্লাস সম্পর্কে সমস্ত প্রয়োজনীয় তথ্য শিখতে সক্ষম। তদনুসারে, আপনি যখন Cat
পশুচিকিত্সা ক্লিনিক ক্লাসের পদ্ধতিতে একটি বস্তু পাস করেনmain()
পদ্ধতি, প্রোগ্রাম ইতিমধ্যেই জানে যে এটি একটি বিড়াল, কুকুর নয়। এখন কল্পনা করা যাক যে আমরা একটি ভিন্ন টাস্কের মুখোমুখি হয়েছি। আমাদের লক্ষ্য একটি কোড বিশ্লেষক লিখতে হয়. CodeAnalyzer
আমাদের একটি একক পদ্ধতি সহ একটি ক্লাস তৈরি করতে হবে : void analyzeObject(Object o)
. এই পদ্ধতি উচিত:
- এটিতে পাস করা বস্তুর ক্লাস নির্ধারণ করুন এবং কনসোলে ক্লাসের নাম প্রদর্শন করুন;
- পাস করা ক্লাসের সমস্ত ক্ষেত্রের নাম নির্ধারণ করুন, ব্যক্তিগতগুলি সহ, এবং সেগুলিকে কনসোলে প্রদর্শন করুন;
- ব্যক্তিগত সহ পাস করা ক্লাসের সমস্ত পদ্ধতির নাম নির্ধারণ করুন এবং সেগুলি কনসোলে প্রদর্শন করুন।
public class CodeAnalyzer {
public static void analyzeClass(Object o) {
// Print the name of the class of object o
// Print the names of all variables of this class
// Print the names of all methods of this class
}
}
এখন আমরা স্পষ্টভাবে দেখতে পাচ্ছি যে এই টাস্কটি আপনার পূর্বে সমাধান করা অন্যান্য কাজের থেকে কীভাবে আলাদা। আমাদের বর্তমান উদ্দেশ্যের সাথে, অসুবিধাটি এই সত্য যে আমরা বা প্রোগ্রামটি কেউই জানি না যে ঠিক কী পাস করা হবেanalyzeClass()
পদ্ধতি আপনি যদি এই ধরনের একটি প্রোগ্রাম লেখেন, অন্য প্রোগ্রামাররা এটি ব্যবহার করা শুরু করবে এবং তারা এই পদ্ধতিতে কিছু পাস করতে পারে — যেকোনো স্ট্যান্ডার্ড জাভা ক্লাস বা অন্য কোনো ক্লাস তারা লেখে। পাস করা ক্লাসে যেকোন সংখ্যক ভেরিয়েবল এবং পদ্ধতি থাকতে পারে। অন্য কথায়, আমাদের (এবং আমাদের প্রোগ্রাম) কোন ধারণা নেই যে আমরা কোন ক্লাস নিয়ে কাজ করব। কিন্তু তবুও, আমাদের এই কাজটি সম্পূর্ণ করতে হবে। এবং এখানেই স্ট্যান্ডার্ড জাভা রিফ্লেকশন এপিআই আমাদের সাহায্যে আসে। প্রতিফলন API ভাষার একটি শক্তিশালী টুল। ওরাকলের অফিসিয়াল ডকুমেন্টেশন সুপারিশ করে যে এই পদ্ধতিটি শুধুমাত্র অভিজ্ঞ প্রোগ্রামারদের দ্বারা ব্যবহার করা উচিত যারা জানেন তারা কী করছেন। আপনি শীঘ্রই বুঝতে পারবেন কেন আমরা এই ধরণের সতর্কতা আগে থেকেই দিচ্ছি :) এখানে আপনি প্রতিফলন API এর সাথে করতে পারেন এমন একটি তালিকা রয়েছে:
- একটি বস্তুর শ্রেণী সনাক্ত/নির্ধারণ করুন।
- ক্লাস মডিফায়ার, ক্ষেত্র, পদ্ধতি, ধ্রুবক, কনস্ট্রাক্টর এবং সুপারক্লাস সম্পর্কে তথ্য পান।
- কোন পদ্ধতি বাস্তবায়িত ইন্টারফেসের অন্তর্গত তা খুঁজে বের করুন।
- একটি ক্লাসের একটি উদাহরণ তৈরি করুন যার ক্লাসের নাম প্রোগ্রামটি কার্যকর না হওয়া পর্যন্ত জানা যায় না।
- নাম দ্বারা একটি উদাহরণ ক্ষেত্রের মান পান এবং সেট করুন।
- নাম দ্বারা একটি উদাহরণ পদ্ধতি কল করুন.
কিভাবে একটি বস্তুর শ্রেণী সনাক্ত/নির্ধারণ করতে হয়
বেসিক দিয়ে শুরু করা যাক। জাভা প্রতিফলন ইঞ্জিনের প্রবেশ বিন্দু হলClass
ক্লাস। হ্যাঁ, এটা সত্যিই মজার দেখায়, কিন্তু এটা কি প্রতিফলন :) Class
ক্লাস ব্যবহার করে, আমরা প্রথমে আমাদের পদ্ধতিতে পাস করা কোনো বস্তুর শ্রেণী নির্ধারণ করি। আসুন এটি করার চেষ্টা করি:
import learn.codegym.Cat;
public class CodeAnalyzer {
public static void analyzeClass(Object o) {
Class clazz = o.getClass();
System.out.println(clazz);
}
public static void main(String[] args) {
analyzeClass(new Cat("Fluffy", 6));
}
}
কনসোল আউটপুট:
class learn.codegym.Cat
দুটি বিষয়ে মনোযোগ দিন। প্রথমত, আমরা ইচ্ছাকৃতভাবে Cat
ক্লাসটিকে একটি পৃথক learn.codegym
প্যাকেজে রাখি। এখন আপনি দেখতে পাচ্ছেন যে getClass()
পদ্ধতিটি ক্লাসের পুরো নাম প্রদান করে। দ্বিতীয়ত, আমরা আমাদের ভেরিয়েবলের নাম দিয়েছি clazz
। যে একটু অদ্ভুত দেখায়. এটাকে "ক্লাস" বলাটা বোধগম্য হবে, কিন্তু "ক্লাস" জাভাতে একটি সংরক্ষিত শব্দ। কম্পাইলার ভেরিয়েবলকে এটি বলা যাবে না। আমরা একরকম যে কাছাকাছি পেতে ছিল :) একটি শুরু জন্য খারাপ না! আমাদের সামর্থ্যের তালিকায় আর কী ছিল?
কিভাবে ক্লাস মডিফায়ার, ক্ষেত্র, পদ্ধতি, ধ্রুবক, কনস্ট্রাক্টর এবং সুপারক্লাস সম্পর্কে তথ্য পেতে হয়।
এখন জিনিস আরো আকর্ষণীয় হচ্ছে! বর্তমান ক্লাসে, আমাদের কোন ধ্রুবক বা অভিভাবক শ্রেণী নেই। একটি সম্পূর্ণ ছবি তৈরি করতে তাদের যোগ করা যাক। সহজতমAnimal
অভিভাবক শ্রেণী তৈরি করুন:
package learn.codegym;
public class Animal {
private String name;
private int age;
}
এবং আমরা আমাদের Cat
ক্লাসকে উত্তরাধিকারী করব Animal
এবং একটি ধ্রুবক যোগ করব:
package learn.codegym;
public class Cat extends Animal {
private static final String ANIMAL_FAMILY = "Feline family";
private String name;
private int age;
// ...the rest of the class
}
এখন আমরা সম্পূর্ণ ছবি আছে! আসুন দেখি প্রতিফলন কী করতে সক্ষম :)
import learn.codegym.Cat;
import java.util.Arrays;
public class CodeAnalyzer {
public static void analyzeClass(Object o) {
Class clazz = o.getClass();
System.out.println("Class name: " + clazz);
System.out.println("Class fields: " + Arrays.toString(clazz.getDeclaredFields()));
System.out.println("Parent class: " + clazz.getSuperclass());
System.out.println("Class methods: " + Arrays.toString(clazz.getDeclaredMethods()));
System.out.println("Class constructors: " + Arrays.toString(clazz.getConstructors()));
}
public static void main(String[] args) {
analyzeClass(new Cat("Fluffy", 6));
}
}
কনসোলে আমরা যা দেখি তা এখানে:
Class name: class learn.codegym.Cat
Class fields: [private static final java.lang.String learn.codegym.Cat.ANIMAL_FAMILY, private java.lang.String learn.codegym.Cat.name, private int learn.codegym.Cat.age]
Parent class: class learn.codegym.Animal
Class methods: [public java.lang.String learn.codegym.Cat.getName(), public void learn.codegym.Cat.setName(java.lang.String), public void learn.codegym.Cat.sayMeow(), public void learn.codegym.Cat.setAge(int), public void learn.codegym.Cat.jump(), public int learn.codegym.Cat.getAge()]
Class constructors: [public learn.codegym.Cat(java.lang.String, int)]
আমরা পেতে সক্ষম ছিল যে সব বিস্তারিত ক্লাস তথ্য দেখুন! আর শুধু জনসাধারণের তথ্য নয়, ব্যক্তিগত তথ্যও! বিঃদ্রঃ: private
ভেরিয়েবলগুলিও তালিকায় প্রদর্শিত হয়। আমাদের ক্লাসের "বিশ্লেষণ" মূলত সম্পূর্ণরূপে বিবেচিত হতে পারে: আমরা analyzeObject()
যা করতে পারি তা শিখতে পদ্ধতিটি ব্যবহার করছি। কিন্তু প্রতিফলন দিয়ে আমরা যা করতে পারি তা নয়। আমরা সাধারণ পর্যবেক্ষণে সীমাবদ্ধ নই — আমরা পদক্ষেপ নেওয়ার দিকে এগিয়ে যাব! :)
কিভাবে একটি ক্লাসের একটি উদাহরণ তৈরি করতে হয় যার ক্লাসের নাম প্রোগ্রামটি কার্যকর না হওয়া পর্যন্ত জানা যায় না।
ডিফল্ট কনস্ট্রাক্টর দিয়ে শুরু করা যাক। আমাদেরCat
ক্লাসে এখনও একটি নেই, তাই এটি যোগ করা যাক:
public Cat() {
}
Cat
প্রতিফলন ( createCat()
পদ্ধতি) ব্যবহার করে একটি অবজেক্ট তৈরি করার কোডটি এখানে রয়েছে :
import learn.codegym.Cat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static Cat createCat() throws IOException, IllegalAccessException, InstantiationException, ClassNotFoundException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String className = reader.readLine();
Class clazz = Class.forName(className);
Cat cat = (Cat) clazz.newInstance();
return cat;
}
public static Object createObject() throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String className = reader.readLine();
Class clazz = Class.forName(className);
Object result = clazz.newInstance();
return result;
}
public static void main(String[] args) throws IOException, IllegalAccessException, ClassNotFoundException, InstantiationException {
System.out.println(createCat());
}
}
কনসোল ইনপুট:
learn.codegym.Cat
কনসোল আউটপুট:
Cat{name='null', age=0}
এটি একটি ত্রুটি নয়: এর মান name
এবং age
কনসোলে প্রদর্শিত হয় কারণ আমরা toString()
ক্লাসের পদ্ধতিতে তাদের আউটপুট করার জন্য কোড লিখেছিলাম Cat
। এখানে আমরা একটি ক্লাসের নাম পড়ি যার অবজেক্ট আমরা কনসোল থেকে তৈরি করব। প্রোগ্রামটি ক্লাসের নাম চিনতে পারে যার অবজেক্ট তৈরি করা হবে। 
newInstance()
করে , আমরা এই শ্রেণীর একটি নতুন অবজেক্ট তৈরি করি। এটা অন্য ব্যাপার যদিCat
কনস্ট্রাক্টর ইনপুট হিসাবে আর্গুমেন্ট নেয়। ক্লাসের ডিফল্ট কনস্ট্রাক্টরটি সরিয়ে দিন এবং আবার আমাদের কোড চালানোর চেষ্টা করুন।
null
java.lang.InstantiationException: learn.codegym.Cat
at java.lang.Class.newInstance(Class.java:427)
কিছু ভুল হয়েছে! আমরা একটি ত্রুটি পেয়েছি কারণ আমরা ডিফল্ট কনস্ট্রাক্টর ব্যবহার করে একটি অবজেক্ট তৈরি করার জন্য একটি পদ্ধতি কল করেছি। কিন্তু আমরা এখন যেমন একটি কনস্ট্রাক্টর নেই. সুতরাং যখন newInstance()
পদ্ধতিটি চলে, প্রতিফলন প্রক্রিয়া দুটি পরামিতি সহ আমাদের পুরানো কনস্ট্রাক্টর ব্যবহার করে:
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
কিন্তু আমরা পরামিতিগুলির সাথে কিছু করিনি, যেন আমরা তাদের সম্পর্কে সম্পূর্ণ ভুলে গেছি! কনস্ট্রাক্টরের কাছে আর্গুমেন্ট দেওয়ার জন্য প্রতিফলন ব্যবহার করার জন্য একটু "সৃজনশীলতা" প্রয়োজন:
import learn.codegym.Cat;
import java.lang.reflect.InvocationTargetException;
public class Main {
public static Cat createCat() {
Class clazz = null;
Cat cat = null;
try {
clazz = Class.forName("learn.codegym.Cat");
Class[] catClassParams = {String.class, int.class};
cat = (Cat) clazz.getConstructor(catClassParams).newInstance("Fluffy", 6);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return cat;
}
public static void main(String[] args) {
System.out.println(createCat());
}
}
কনসোল আউটপুট:
Cat{name='Fluffy', age=6}
আসুন আমাদের প্রোগ্রামে কী ঘটছে তা ঘনিষ্ঠভাবে দেখে নেওয়া যাক। আমরা অবজেক্টের একটি অ্যারে তৈরি করেছি Class
।
Class[] catClassParams = {String.class, int.class};
তারা আমাদের কনস্ট্রাক্টরের পরামিতিগুলির সাথে মিলে যায় (যাতে শুধু আছে String
এবং int
পরামিতি)। আমরা তাদের পদ্ধতিতে পাস করি clazz.getConstructor()
এবং পছন্দসই কনস্ট্রাক্টরের অ্যাক্সেস লাভ করি। এর পরে, আমাদের যা করতে হবে তা হল newInstance()
প্রয়োজনীয় আর্গুমেন্ট সহ মেথডটিকে কল করতে হবে, এবং অবজেক্টটিকে স্পষ্টভাবে কাঙ্খিত টাইপে কাস্ট করতে ভুলবেন না Cat
:।
cat = (Cat) clazz.getConstructor(catClassParams).newInstance("Fluffy", 6);
এখন আমাদের বস্তু সফলভাবে তৈরি করা হয়েছে! কনসোল আউটপুট:
Cat{name='Fluffy', age=6}
ঠিক বরাবর চলছি :)
কিভাবে নাম দ্বারা একটি উদাহরণ ক্ষেত্রের মান পেতে এবং সেট করতে হয়।
কল্পনা করুন যে আপনি অন্য প্রোগ্রামার দ্বারা লিখিত একটি ক্লাস ব্যবহার করছেন। উপরন্তু, আপনার এটি সম্পাদনা করার ক্ষমতা নেই। উদাহরণস্বরূপ, একটি JAR-এ প্যাকেজ করা একটি রেডিমেড ক্লাস লাইব্রেরি। আপনি ক্লাসের কোড পড়তে পারেন, কিন্তু আপনি এটি পরিবর্তন করতে পারবেন না। ধরুন যে প্রোগ্রামার যিনি এই লাইব্রেরিতে একটি ক্লাস তৈরি করেছেন (এটি আমাদের পুরানোCat
ক্লাস হতে দিন), ডিজাইনটি চূড়ান্ত করার আগের রাতে পর্যাপ্ত ঘুম পেতে ব্যর্থ হয়ে মাঠের জন্য গেটার এবং সেটার সরিয়ে ফেললেন age
। এখন এই ক্লাস আপনার কাছে এসেছে। এটি আপনার সমস্ত চাহিদা পূরণ করে, যেহেতু Cat
আপনার প্রোগ্রামে আপনার কেবলমাত্র বস্তুর প্রয়োজন। কিন্তু আপনি তাদের একটি ক্ষেত্র আছে প্রয়োজন age
! এটি একটি সমস্যা: আমরা মাঠে পৌঁছাতে পারি না, কারণ এটি রয়েছেprivate
সংশোধক, এবং গেটার এবং সেটটারটি ঘুম-বঞ্চিত বিকাশকারী দ্বারা মুছে ফেলা হয়েছিল যিনি ক্লাস তৈরি করেছিলেন :/ ভাল, প্রতিফলন এই পরিস্থিতিতে আমাদের সাহায্য করতে পারে! আমাদের ক্লাসের কোডে অ্যাক্সেস আছে Cat
, তাই আমরা অন্তত জানতে পারি এর কোন ক্ষেত্র রয়েছে এবং তাদের কী বলা হয়। এই তথ্য দিয়ে সশস্ত্র, আমরা আমাদের সমস্যার সমাধান করতে পারি:
import learn.codegym.Cat;
import java.lang.reflect.Field;
public class Main {
public static Cat createCat() {
Class clazz = null;
Cat cat = null;
try {
clazz = Class.forName("learn.codegym.Cat");
cat = (Cat) clazz.newInstance();
// We got lucky with the name field, since it has a setter
cat.setName("Fluffy");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(cat, 6);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return cat;
}
public static void main(String[] args) {
System.out.println(createCat());
}
}
মন্তব্যে যেমন বলা হয়েছে, name
ক্ষেত্র সহ সবকিছুই সোজা, যেহেতু ক্লাস ডেভেলপাররা একটি সেটার প্রদান করেছে। আপনি ইতিমধ্যেই জানেন কিভাবে ডিফল্ট কনস্ট্রাক্টর থেকে অবজেক্ট তৈরি করতে হয়: newInstance()
এর জন্য আমাদের কাছে আছে। কিন্তু আমাদের দ্বিতীয় ক্ষেত্রের সাথে কিছু টেঙ্কারিং করতে হবে। আসুন এখানে কি ঘটছে তা খুঁজে বের করা যাক :)
Field age = clazz.getDeclaredField("age");
এখানে, আমাদের Class clazz
অবজেক্ট ব্যবহার করে, আমরা পদ্ধতির age
মাধ্যমে ক্ষেত্রটি অ্যাক্সেস করি getDeclaredField()
। Field age
এটি আমাদেরকে একটি বস্তু হিসাবে বয়স ক্ষেত্র পেতে দেয় । কিন্তু এটি যথেষ্ট নয়, কারণ আমরা কেবল ক্ষেত্রগুলিতে মান নির্ধারণ করতে পারি না private
। এটি করার জন্য, আমাদের পদ্ধতিটি ব্যবহার করে ক্ষেত্রটিকে অ্যাক্সেসযোগ্য করতে হবে setAccessible()
:
age.setAccessible(true);
একবার আমরা একটি ক্ষেত্রে এটি করি, আমরা একটি মান নির্ধারণ করতে পারি:
age.set(cat, 6);
আপনি দেখতে পাচ্ছেন, আমাদের Field age
অবজেক্টের এক ধরনের ইনসাইড-আউট সেটার রয়েছে যেখানে আমরা একটি int মান পাস করি এবং অবজেক্টের ক্ষেত্রটি বরাদ্দ করা হয়। আমরা আমাদের main()
পদ্ধতি চালান এবং দেখুন:
Cat{name='Fluffy', age=6}
চমৎকার! আমরা এটা করেছি! :) দেখা যাক আর কি করা যায়...
নাম দ্বারা একটি উদাহরণ পদ্ধতি কল কিভাবে.
আগের উদাহরণে পরিস্থিতি কিছুটা পরিবর্তন করা যাক। ধরা যাক যেCat
ক্লাস ডেভেলপার গেটার এবং সেটারের সাথে ভুল করেনি। সে ক্ষেত্রে সবকিছু ঠিক আছে। এখন সমস্যাটি ভিন্ন: একটি পদ্ধতি রয়েছে যা আমাদের অবশ্যই প্রয়োজন, কিন্তু বিকাশকারী এটিকে ব্যক্তিগত করেছে:
private void sayMeow() {
System.out.println("Meow!");
}
এর মানে হল যে যদি আমরা আমাদের প্রোগ্রামে অবজেক্ট তৈরি করি , তাহলে আমরা তাদের উপর মেথড Cat
কল করতে পারব না । sayMeow()
আমরা কি বিড়াল পাব যে মেও না? এটা অদ্ভুত :/ আমরা কিভাবে এটা ঠিক করব? আবারও, প্রতিফলন API আমাদের সাহায্য করে! আমরা আমাদের প্রয়োজন পদ্ধতির নাম জানি. অন্য সবকিছু একটি প্রযুক্তিগত:
import learn.codegym.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void invokeSayMeowMethod() {
Class clazz = null;
Cat cat = null;
try {
cat = new Cat("Fluffy", 6);
clazz = Class.forName(Cat.class.getName());
Method sayMeow = clazz.getDeclaredMethod("sayMeow");
sayMeow.setAccessible(true);
sayMeow.invoke(cat);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
invokeSayMeowMethod();
}
}
এখানে আমরা একই জিনিসের অনেক কিছু করি যা আমরা একটি ব্যক্তিগত ক্ষেত্রে অ্যাক্সেস করার সময় করেছি। প্রথমত, আমরা আমাদের প্রয়োজনীয় পদ্ধতিটি পাই। এটি একটি Method
বস্তুর মধ্যে আবদ্ধ করা হয়েছে:
Method sayMeow = clazz.getDeclaredMethod("sayMeow");
পদ্ধতিটি getDeclaredMethod()
আমাদের ব্যক্তিগত পদ্ধতিতে যেতে দেয়। এর পরে, আমরা পদ্ধতিটিকে কলযোগ্য করি:
sayMeow.setAccessible(true);
এবং অবশেষে, আমরা পছন্দসই বস্তুর উপর পদ্ধতি কল করি:
sayMeow.invoke(cat);
এখানে, আমাদের পদ্ধতি কলটি একটি "কলব্যাক" এর মত দেখাচ্ছে: আমরা একটি অবজেক্টকে পছন্দসই পদ্ধতিতে নির্দেশ করার জন্য একটি সময়কাল ব্যবহার করতে অভ্যস্ত হয়েছি ( cat.sayMeow()
), কিন্তু প্রতিফলনের সাথে কাজ করার সময়, আমরা যে পদ্ধতিতে কল করতে চাই সেটির দিকে চলে যাই। যে পদ্ধতি আমাদের কনসোলে কি আছে?
Meow!
সব কাজ! :) এখন আপনি জাভা এর প্রতিফলন প্রক্রিয়া আমাদের যে বিশাল সম্ভাবনা দেয় তা দেখতে পারেন। কঠিন এবং অপ্রত্যাশিত পরিস্থিতিতে (যেমন একটি বন্ধ লাইব্রেরি থেকে ক্লাস সহ আমাদের উদাহরণ), এটি সত্যিই আমাদের অনেক সাহায্য করতে পারে। কিন্তু, যে কোনো মহান শক্তির মতো, এটি মহান দায়িত্ব নিয়ে আসে। প্রতিফলনের অসুবিধাগুলি ওরাকল ওয়েবসাইটের একটি বিশেষ বিভাগে বর্ণনা করা হয়েছে। তিনটি প্রধান অসুবিধা আছে:
-
পারফরম্যান্স খারাপ। প্রতিফলন ব্যবহার করে বলা পদ্ধতিগুলির কার্যক্ষমতা স্বাভাবিক পদ্ধতির চেয়ে খারাপ।
-
নিরাপত্তা বিধিনিষেধ আছে। প্রতিফলন পদ্ধতি আমাদের রানটাইমে একটি প্রোগ্রামের আচরণ পরিবর্তন করতে দেয়। কিন্তু আপনার কর্মক্ষেত্রে, একটি বাস্তব প্রকল্পে কাজ করার সময়, আপনি সীমাবদ্ধতার সম্মুখীন হতে পারেন যা এটি অনুমোদন করে না।
-
অভ্যন্তরীণ তথ্য প্রকাশের ঝুঁকি। এটা বোঝা গুরুত্বপূর্ণ যে প্রতিফলন হল এনক্যাপসুলেশন নীতির সরাসরি লঙ্ঘন: এটি আমাদের ব্যক্তিগত ক্ষেত্র, পদ্ধতি ইত্যাদি অ্যাক্সেস করতে দেয়। আমি মনে করি না যে OOP-এর নীতিগুলির একটি সরাসরি এবং স্পষ্ট লঙ্ঘনকে অবলম্বন করা উচিত বলে উল্লেখ করার প্রয়োজন আছে। শুধুমাত্র সবচেয়ে চরম ক্ষেত্রে, যখন আপনার নিয়ন্ত্রণের বাইরের কারণে সমস্যা সমাধানের অন্য কোন উপায় নেই।
GO TO FULL VERSION