জাভার Generics ফিচারটি টাইপ সেফটি নিশ্চিত করে এবং কোডের পুনঃব্যবহারযোগ্যতা বাড়ায়। যখন জাভায় Generics ব্যবহার করা হয়, তখন সাধারণভাবে আপনি টাইপ প্যারামিটার ব্যবহার করে এমন ক্লাস বা মেথড তৈরি করেন যা নির্দিষ্ট টাইপের উপর কাজ করে। কিন্তু Reflection ব্যবহারের সময় Generics এবং টাইপ প্যারামিটার অ্যাক্সেস করাটা একটু জটিল হয়ে থাকে, কারণ রিফ্লেকশন রানটাইমে টাইপ সম্পর্কিত তথ্য ঠিকভাবে ধরে রাখে না (এটি type erasure এর কারণে ঘটে)।
Generics এবং Type Parameters - কী?
- Generics একটি ধারণা, যা আপনাকে টাইপ প্যারামিটার ব্যবহার করে ক্লাস, ইন্টারফেস বা মেথড তৈরি করার সুযোগ দেয়। এর ফলে একই কোড বিভিন্ন ধরনের ডেটার সাথে কাজ করতে সক্ষম হয়।
- Type Parameters: যখন আপনি জেনেরিক ক্লাস বা মেথড তৈরি করেন, তখন আপনি টাইপ প্যারামিটার নির্দিষ্ট করেন যা রuntime এ টেমপ্লেট হিসেবে কাজ করে।
Type Erasure:
জাভাতে Generics এর একটি বিশেষ বৈশিষ্ট্য হলো type erasure। এর মানে হচ্ছে যে, যখন কোড কম্পাইল হয়, টাইপ প্যারামিটারগুলি সরিয়ে ফেলা হয় এবং জেনেরিক টাইপগুলি তাদের ক্লাস টাইপে রূপান্তরিত হয়। এটি রানটাইমে টাইপের সঠিক তথ্য নষ্ট করে ফেলে, ফলে রিফ্লেকশনে জেনেরিক টাইপ এবং টাইপ প্যারামিটারগুলোর উপর কাজ করতে কিছু সীমাবদ্ধতা থাকে।
Generics-এর সাথে Reflection ব্যবহার:
রিফ্লেকশন ব্যবহার করে আপনি Generics ক্লাসের মধ্যে থাকা টাইপ প্যারামিটার এবং তাদের বাস্তব টাইপ অ্যাক্সেস করতে পারেন, কিন্তু সেগুলি কিছু বিশেষ মেথড ব্যবহার করে করতে হবে।
Generics এবং Type Parameters ব্যবহার করার উদাহরণ:
ধরা যাক, আমরা একটি জেনেরিক ক্লাস তৈরি করেছি এবং সেটির টাইপ প্যারামিটার ব্যবহার করে তার সাথে কাজ করতে চাই।
উদাহরণ: Generic Class এবং Reflection
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
class Box<T> {
private T value;
public Box(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
public class ReflectionGenericExample {
public static void main(String[] args) {
try {
// Step 1: Create an instance of the generic class
Box<String> box = new Box<>("Hello, Reflection!");
// Step 2: Get the Class object for the Box class
Class<?> boxClass = box.getClass();
// Step 3: Get the generic type parameter used in Box class (String)
Type genericSuperclass = boxClass.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
// Step 4: Get the type argument used in Box
Type typeArgument = parameterizedType.getActualTypeArguments()[0];
System.out.println("Generic type argument: " + typeArgument.getTypeName()); // Output: java.lang.String
} catch (Exception e) {
e.printStackTrace();
}
}
}
কোড বিশ্লেষণ:
- Box Class:
Box<T>একটি জেনেরিক ক্লাস যা একটিTটাইপের ভ্যালু রাখে এবং সেই ভ্যালু ফেরত দেয়।Box<String>টাইপ প্যারামিটার হিসাবেStringব্যবহার করে আমরা এই ক্লাসের একটি অবজেক্ট তৈরি করেছি।
- Class এবং getGenericSuperclass():
box.getClass()ব্যবহার করে আমরাBoxক্লাসেরClassঅবজেক্ট পাই।getGenericSuperclass()মেথডটি একটি জেনেরিক সুপারক্লাসের ক্ষেত্রে টাইপ সম্পর্কিত তথ্য প্রদান করে।
- ParameterizedType এবং getActualTypeArguments():
ParameterizedTypeব্যবহার করে, আমরাBoxক্লাসের টাইপ প্যারামিটার অ্যাক্সেস করতে পারি।getActualTypeArguments()মেথডটিBoxক্লাসে ব্যবহৃত টাইপ প্যারামিটারগুলি ফেরত দেয় (এখানে এটিStringটাইপ হবে)।
Generics এবং Reflection সম্পর্কে কিছু গুরুত্বপূর্ণ পয়েন্ট:
- Type Erasure: যখন জেনেরিক ক্লাস বা মেথড রানটাইমে চলে, তখন টাইপ প্যারামিটারগুলি type erasure কারণে সাধারণ টাইপে পরিণত হয়। অর্থাৎ,
Box<String>এবংBox<Integer>রানটাইমে একটাই ক্লাসBoxহয়ে থাকে। - ParameterizedType:
ParameterizedTypeক্লাসটি আপনাকে জেনেরিক টাইপ প্যারামিটারটি অ্যাক্সেস করার সুযোগ দেয়, যখন আপনি একটি জেনেরিক ক্লাসের টাইপ ইনফরমেশন চান।- এর মাধ্যমে আপনি
getActualTypeArguments()মেথডের মাধ্যমে টাইপ প্যারামিটার (যেমনStringবাInteger) এর টাইপ পেতে পারেন।
- Generics with Methods:
- রিফ্লেকশন ব্যবহার করে আপনি জেনেরিক মেথডের প্যারামিটার এবং রিটার্ন টাইপও জানতে পারেন। এর জন্য আপনি
Method.getGenericParameterTypes()এবংMethod.getGenericReturnType()মেথড ব্যবহার করতে পারেন।
- রিফ্লেকশন ব্যবহার করে আপনি জেনেরিক মেথডের প্যারামিটার এবং রিটার্ন টাইপও জানতে পারেন। এর জন্য আপনি
উদাহরণ: Generic Method Reflection:
import java.lang.reflect.Method;
import java.lang.reflect.Type;
class Example {
public <T> void display(T t) {
System.out.println("Value: " + t);
}
}
public class ReflectionGenericMethodExample {
public static void main(String[] args) {
try {
// Step 1: Get the Method object for the generic method
Method method = Example.class.getMethod("display", Object.class);
// Step 2: Get the generic return type
Type returnType = method.getGenericReturnType();
System.out.println("Return Type: " + returnType.getTypeName()); // Output: void
// Step 3: Get the generic parameter types
Type[] parameterTypes = method.getGenericParameterTypes();
for (Type type : parameterTypes) {
System.out.println("Parameter Type: " + type.getTypeName()); // Output: java.lang.Object
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Generics এবং Type Parameters ব্যবহার করে জেনেরিক ক্লাস এবং মেথড তৈরি করা যায়, যা আরও ডাইনামিক এবং টাইপ সেফ কোড তৈরি করতে সাহায্য করে।
- Reflection ব্যবহার করে আপনি জেনেরিক ক্লাস এবং মেথডের টাইপ প্যারামিটার এবং তাদের বাস্তব টাইপ জানতে পারেন, তবে টাইপ ইরেজার এবং টাইপ ইনফরমেশন অ্যাক্সেসের কিছু সীমাবদ্ধতা থাকে।
- ParameterizedType এবং Method.getGenericParameterTypes() এর মতো মেথডগুলো আপনাকে রিফ্লেকশন ব্যবহারে জেনেরিক টাইপ এবং প্যারামিটার পেতে সহায়তা করে।
Generics হল একটি শক্তিশালী বৈশিষ্ট্য যা জাভায় টাইপ সেফটি বজায় রেখে কোলেকশন এবং অন্যান্য ডেটা স্ট্রাকচারগুলি আরও সাধারণ এবং পুনঃব্যবহারযোগ্য করে তোলে। জাভায় Generics ব্যবহার করে আপনি টাইপের নির্দিষ্টতা (type safety) বজায় রেখে কোড লেখার সুবিধা পান, যেমন List<String> বা Map<Integer, String> টাইপগুলি।
Generics কি?
Generics জাভায় একটি কনসেপ্ট যা আপনাকে টাইপ প্যারামিটার হিসেবে ব্যবহার করতে দেয়। এর মাধ্যমে আপনি ক্লাস, ইন্টারফেস, বা মেথডের মধ্যে টাইপের সাধারণতা বজায় রাখতে পারেন। এতে কোডের পুনঃব্যবহারযোগ্যতা এবং টাইপ সেফটি উন্নত হয়।
উদাহরণ:
// Generics ব্যবহার করে List তৈরি
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
// List এর উপাদানগুলি টাইপ সেফ
String element = list.get(0); // টাইপ সেফটি বজায় থাকে
Generics এর সাথে Reflection:
রিফ্লেকশন ব্যবহার করে আপনি জাভার টাইপ প্যারামিটার (Generic Type) গুলি রানটাইমে অ্যাক্সেস করতে পারেন, যদিও Generics সাধারণত রানটাইমে মুছে যায় (type erasure) এবং রানটাইমে তাদের প্রকৃত টাইপের তথ্য সরাসরি অ্যাক্সেস করা সম্ভব নয়।
তবে, রিফ্লেকশন দিয়ে আপনি Generic Type সম্পর্কে কিছু তথ্য পেতে পারেন। উদাহরণস্বরূপ, আপনি কোন List<T> অথবা Map<K, V> এ কোন টাইপ ব্যবহার করা হচ্ছে তা রিফ্লেকশন ব্যবহার করে জানার চেষ্টা করতে পারেন।
Generics এর সাথে Reflection এর ব্যবহার:
1. Generic Type এর তথ্য সংগ্রহ করা:
রিফ্লেকশন ব্যবহার করে আপনি টাইপ প্যারামিটারগুলো এক্সট্র্যাক্ট করতে পারেন, যদিও Generics টাইপ ইরেজ (type erasure) দ্বারা রানটাইমে মুছে যায়।
এটি করতে হলে আপনি ParameterizedType ইন্টারফেস ব্যবহার করতে হবে, যা আপনাকে টাইপ প্যারামিটার সম্পর্কিত তথ্য প্রদান করে।
উদাহরণ: Generic Type এর তথ্য রিফ্লেকশন দিয়ে অ্যাক্সেস করা
import java.lang.reflect.*;
class MyClass<T> {
private T value;
public MyClass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
public class GenericReflectionExample {
public static void main(String[] args) throws Exception {
// MyClass এর একটি ইনস্ট্যান্স তৈরি করি যেখানে T = String
MyClass<String> myObject = new MyClass<>("Hello, Generics!");
// Class অবজেক্টের মাধ্যমে রিফ্লেকশন ব্যবহার
Class<?> clazz = myObject.getClass();
// ফিল্ডের তথ্য পেতে
Field field = clazz.getDeclaredField("value");
// ParameterizedType ব্যবহার করে Generic Type এর তথ্য পেতে
Type fieldType = field.getGenericType();
// ফিল্ডের টাইপ বের করা
if (fieldType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
Type[] typeArgs = parameterizedType.getActualTypeArguments();
// Generic Type এর তথ্য বের করা
for (Type typeArg : typeArgs) {
System.out.println("Generic Type: " + typeArg.getTypeName());
}
}
// ফিল্ডের মান প্রিন্ট করা
System.out.println("Field Value: " + field.get(myObject));
}
}
আউটপুট:
Generic Type: java.lang.String
Field Value: Hello, Generics!
ব্যাখ্যা:
MyClass<T>: এখানেTহলো Generic টাইপ।MyClass<String>ব্যবহার করলেTটাইপ হবেString।getDeclaredField("value"): এই মেথডটি ক্লাসের একটি ফিল্ডের রিফ্লেকশন অবজেক্ট পায়, যেটিvalueফিল্ড।getGenericType():valueফিল্ডের টাইপকেTypeরিটার্ন করে, এবং এটি যদিParameterizedTypeহয়, তাহলেgetActualTypeArguments()মেথডের মাধ্যমে টাইপ প্যারামিটার অ্যাক্সেস করা যায়।ParameterizedType: এটি টাইপ প্যারামিটারগুলোর বিশদ তথ্য প্রদান করে, যেমন ফিল্ড বা মেথডে ব্যবহৃত টাইপ প্যারামিটার।
Generics এবং Reflection: কিছু গুরুত্বপূর্ণ বিষয়:
- টাইপ ইরেজ (Type Erasure):
- Java Generics এর অন্যতম বৈশিষ্ট্য হলো টাইপ ইরেজ (type erasure)। এর মানে হচ্ছে, কম্পাইল টাইমে নির্ধারিত টাইপ প্যারামিটারগুলো রানটাইমে মুছে যায়, এবং আপনি রানটাইমে ঠিক যে টাইপ প্যারামিটার ব্যবহার করা হয়েছে তা জানতে পারেন না।
ParameterizedType:- রিফ্লেকশন ব্যবহার করে আপনি যখন Generic টাইপ অ্যাক্সেস করেন, তখন
ParameterizedTypeইন্টারফেসের মাধ্যমে টাইপ প্যারামিটার পাওয়া যায়।
- রিফ্লেকশন ব্যবহার করে আপনি যখন Generic টাইপ অ্যাক্সেস করেন, তখন
- Generic Type Access:
- ক্লাসের টাইপ:
getGenericSuperclass()এবংgetGenericInterfaces()মেথড ব্যবহার করে ক্লাসের সুপারক্লাস বা ইন্টারফেসের জেনেরিক টাইপও রিফ্লেকশন দিয়ে অ্যাক্সেস করা সম্ভব।
- ক্লাসের টাইপ:
Generics এবং Reflection একসাথে ব্যবহারের মাধ্যমে আপনি টাইপ প্যারামিটার এবং টাইপ সম্পর্কিত তথ্য রানটাইমে অ্যাক্সেস করতে পারেন। তবে, টাইপ ইরেজ কারণে রানটাইমে জেনেরিক টাইপের মূল তথ্য পাওয়া সম্ভব না হলেও, ParameterizedType এর মাধ্যমে কিছু তথ্য উদ্ধার করা সম্ভব। এই বৈশিষ্ট্যটি জাভাতে আরও ডাইনামিক এবং শক্তিশালী কাস্টম লজিক তৈরি করতে সাহায্য করে, বিশেষ করে ফ্রেমওয়ার্ক বা লাইব্রেরি তৈরির ক্ষেত্রে।
Java Reflection API মূলত একটি ক্লাস, মেথড, ফিল্ড বা কনস্ট্রাক্টর সম্পর্কে রuntime ইনফরমেশন পাওয়ার জন্য ব্যবহৃত হয়, এবং এটি গঠনমূলক (generic) কোডের সাথে একত্রিত হয়ে আরও শক্তিশালী এবং ফ্লেক্সিবল হতে পারে। Type Parameters বা Generics ব্যবহারের মাধ্যমে আপনি নির্দিষ্ট টাইপের সাথে কাজ করতে পারেন, কিন্তু যখন আপনি রিফ্লেকশন ব্যবহার করেন, তখন এটি আরও ডাইনামিক এবং ফ্লেক্সিবল হয়।
Type Parameters (Generics) এবং Reflection Integration
Java-তে Generics টাইপ নিরাপত্তা নিশ্চিত করে এবং রানটাইমে টাইপ কনভার্সন বা টাইপ কাস্টিং সংক্রান্ত সমস্যা থেকে মুক্তি দেয়। তবে, রিফ্লেকশন ব্যবহার করার সময় জেনেরিক টাইপগুলি কিছুটা আলাদা দেখায়। রিফ্লেকশন API ব্যবহার করে আপনি টাইপ প্যারামিটারগুলি (যেমন, List<String>) ইন্সপেক্ট (inspect) করতে পারবেন, তবে যেহেতু Generics টাইপ ইনফরমেশন শুধুমাত্র কম্পাইল টাইমে থাকে, এটি রানটাইমে type erasure এর মাধ্যমে মুছে যায়।
রিফ্লেকশন এবং জেনেরিক্স
যেহেতু type erasure এর কারণে রানটাইমে টাইপ প্যারামিটার সরাসরি উপলব্ধ থাকে না, তাই Class<?> বা ParameterizedType ব্যবহার করে আপনি টাইপ প্যারামিটারগুলিকে ইন্সপেক্ট (inspect) করতে পারেন।
Reflection with Generic Types Example:
ধরা যাক, আপনি একটি List<String> টাইপের অবজেক্টে রিফ্লেকশন ব্যবহার করতে চান। টাইপ প্যারামিটার গুলি কম্পাইল টাইমে অ্যাক্সেসযোগ্য, কিন্তু রানটাইমে আপনি এদেরকে Type বা ParameterizedType এর মাধ্যমে অ্যাক্সেস করতে পারবেন।
উদাহরণ: Generics with Reflection
import java.lang.reflect.*;
import java.util.*;
public class GenericReflectionExample {
public static void main(String[] args) throws Exception {
// List<String> টাইপের একটি অবজেক্ট তৈরি
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Reflection");
// List<String> এর টাইপ প্যারামিটার চেক করা
Type listType = list.getClass().getGenericSuperclass();
// ParameterizedType ব্যবহার করে টাইপ প্যারামিটার পাওয়া
if (listType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) listType;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
// টাইপ প্যারামিটার প্রিন্ট করা
for (Type type : typeArguments) {
System.out.println("Type Parameter: " + type.getTypeName());
}
}
}
}
কোডের বিশ্লেষণ:
list.getClass().getGenericSuperclass():- এটি
List<String>এর সুপার ক্লাসের generic type প্রদান করে। তবে,Listএ type erasure হয়ে যাওয়ায় আপনি এর সঠিক টাইপ প্যারামিটারগুলো সরাসরি পেতে পারবেন না। তবে আপনিParameterizedTypeএর মাধ্যমে টাইপ প্যারামিটার পেতে পারবেন।
- এটি
ParameterizedType.getActualTypeArguments():- এই মেথডটি
ParameterizedTypeএর মধ্যে থাকা টাইপ প্যারামিটার গুলোকে অ্যাক্সেস করতে ব্যবহৃত হয়। এটিList<String>এর টাইপ প্যারামিটার হিসাবেStringপ্রিন্ট করবে।
- এই মেথডটি
- Type Parameter::
- যেহেতু
List<String>একটি জেনেরিক টাইপ, রানটাইমে আপনি তার টাইপ প্যারামিটারStringঅ্যাক্সেস করতে পারবেন।
- যেহেতু
Reflection with Generic Methods Example:
এছাড়া আপনি জেনেরিক মেথড এর মাধ্যমে রিফ্লেকশন ব্যবহার করতে পারেন। উদাহরণস্বরূপ:
import java.lang.reflect.*;
class GenericClass<T> {
public void printType(T t) {
System.out.println("Type of T: " + t.getClass().getName());
}
}
public class GenericMethodReflection {
public static void main(String[] args) throws Exception {
// GenericClass<Integer> তৈরি
GenericClass<Integer> obj = new GenericClass<>();
// GenericMethod এর রিফ্লেকশন
Method method = obj.getClass().getMethod("printType", Object.class);
// method.invoke() এর মাধ্যমে মেথড কল করা
method.invoke(obj, 123); // আউটপুট: Type of T: java.lang.Integer
}
}
কোড বিশ্লেষণ:
- GenericClass:
- এখানে
Tহল জেনেরিক টাইপ প্যারামিটার। আপনি যেকোনো টাইপ দিয়ে এটি ইনস্ট্যান্সিয়েট করতে পারেন।
- এখানে
obj.getClass().getMethod("printType", Object.class):- এই রিফ্লেকশন মেথডের মাধ্যমে আপনি জেনেরিক মেথড
printType()-কে অ্যাক্সেস করতে পারেন।
- এই রিফ্লেকশন মেথডের মাধ্যমে আপনি জেনেরিক মেথড
method.invoke(obj, 123);:- এই লাইনটি
printType()মেথডটি কল করে এবংIntegerটাইপের অবজেক্টে123পাস করে, যার ফলে আউটপুট হয় "Type of T: java.lang.Integer"।
- এই লাইনটি
Type Parameters এবং Reflection ব্যবহার করা
- ParameterizedType: এটি Generic Types-এর রানটাইম টাইপ সম্পর্কিত তথ্য সরবরাহ করতে সাহায্য করে।
- Type Erasure: Java-তে টাইপ প্যারামিটারগুলি কম্পাইল টাইমে প্রসেস হয় এবং রানটাইমে তারা বিলীন হয়ে যায়। এর ফলে, টাইপ প্যারামিটার রিফ্লেকশন দ্বারা সরাসরি অ্যাক্সেস করা সম্ভব নয়, তবে ParameterizedType এর মাধ্যমে আপনি কিছুটা ইনফরমেশন পেতে পারেন।
- Type Safety: রিফ্লেকশন এবং জেনেরিক্স একত্রিতভাবে টাইপ নিরাপত্তা কমাতে পারে, তাই রিফ্লেকশন ব্যবহারের সময় কিছু সতর্কতা অবলম্বন করা উচিত।
Java Reflection API এবং Type Parameters (Generics) একত্রিতভাবে ব্যবহার করলে, ডাইনামিক কোডের ক্ষেত্রে আপনি টাইপ প্যারামিটার সম্পর্কিত ইনফরমেশন পেতে এবং তাদের সাথে কাজ করতে পারেন। তবে, type erasure এবং generic types-এর বিশেষ কিছু সীমাবদ্ধতা রয়েছে, যা রানটাইমে টাইপ প্যারামিটার সম্পর্কে সঠিক ইনফরমেশন পাওয়া কিছুটা কঠিন করে তোলে। ParameterizedType এর মাধ্যমে রানটাইমে টাইপ প্যারামিটারগুলিকে অ্যাক্সেস করা সম্ভব হলেও, এটি কিছুটা সীমাবদ্ধ।
Java রিফ্লেকশন প্যাকেজ (java.lang.reflect) ব্যবহার করে Generic Class এবং Generic Methods অ্যাক্সেস করা সম্ভব। তবে, রিফ্লেকশন দিয়ে জেনেরিক টাইপস (generic types) অ্যাক্সেস করার ক্ষেত্রে কিছু সীমাবদ্ধতা রয়েছে, কারণ জেনেরিক টাইপস রানটাইমে type erasure (টাইপ মুছে ফেলা) পদ্ধতির মাধ্যমে বাদ দেওয়া হয়। এর মানে হলো, আপনি যখন জেনেরিক ক্লাস বা মেথড ব্যবহার করেন, তখন জেনেরিক টাইপ রানটাইমে আর উপলব্ধ থাকে না।
1. Generic Class Access
জেনেরিক ক্লাস হলো এমন একটি ক্লাস যা টাইপ প্যারামিটার নিয়ে কাজ করে, যা কোডকে আরও ফ্লেক্সিবল এবং পুনরায় ব্যবহারযোগ্য করে তোলে। রানটাইমে আমরা সাধারণত জেনেরিক ক্লাসের টাইপ প্যারামিটার অ্যাক্সেস করতে পারি না, তবে Reflection এর মাধ্যমে আমরা raw type বা non-generic type অ্যাক্সেস করতে পারি।
উদাহরণ:
import java.lang.reflect.*;
class MyGenericClass<T> {
private T value;
public MyGenericClass(T value) {
this.value = value;
}
public void printValue() {
System.out.println("Value: " + value);
}
}
public class ReflectionExample {
public static void main(String[] args) {
try {
// MyGenericClass<T> এর raw type অ্যাক্সেস করা
Class<?> cls = MyGenericClass.class;
// কনস্ট্রাক্টর খুঁজে বের করা
Constructor<?> constructor = cls.getConstructor(Object.class);
// কনস্ট্রাক্টর ব্যবহার করে অবজেক্ট তৈরি করা
Object obj = constructor.newInstance("Hello, Generics!");
// মেথড অ্যাক্সেস করা
Method method = cls.getMethod("printValue");
// মেথড ইনভোক করা
method.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
ব্যাখ্যা:
- MyGenericClass একটি জেনেরিক ক্লাস যা
Tটাইপ প্যারামিটার নেয়। - রানটাইমে raw type (অর্থাৎ
MyGenericClassক্লাস) অ্যাক্সেস করা হয়েছে এবংObjectটাইপ প্যারামিটার দিয়ে কনস্ট্রাক্টর ইনস্ট্যান্সিয়েট করা হয়েছে। - Reflection এর মাধ্যমে
printValue()মেথড ইনভোক করা হয়েছে।
2. Generic Method Access
একইভাবে, আপনি জেনেরিক মেথডগুলোর রিফ্লেকশন ব্যবহার করে অ্যাক্সেস করতে পারেন, তবে জেনেরিক টাইপ্সের type erasure এর কারণে আপনি মেথডের জেনেরিক টাইপ জানবেন না। কিন্তু আপনি যদি মেথডের প্যারামিটার টাইপ বা রিটার্ন টাইপ রিফ্লেকশন ব্যবহার করে চেক করতে চান, তবে আপনি সেগুলো অ্যাক্সেস করতে পারবেন।
উদাহরণ:
import java.lang.reflect.*;
class MyGenericClass {
// জেনেরিক মেথড
public <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
public class ReflectionExample {
public static void main(String[] args) {
try {
// MyGenericClass ক্লাসের অবজেক্ট তৈরি করা
Class<?> cls = MyGenericClass.class;
MyGenericClass obj = new MyGenericClass();
// জেনেরিক মেথড "printArray" খুঁজে বের করা
Method method = cls.getMethod("printArray", Object[].class);
// মেথড ইনভোক করা
String[] data = {"Hello", "Reflection", "Generics"};
method.invoke(obj, (Object) data);
} catch (Exception e) {
e.printStackTrace();
}
}
}
ব্যাখ্যা:
printArrayএকটি জেনেরিক মেথড যা টাইপ প্যারামিটারTগ্রহণ করে এবং একটি অ্যারে প্রিন্ট করে।- Reflection এর মাধ্যমে
getMethod()ব্যবহার করেprintArrayমেথডটি খুঁজে বের করা হয়েছে, যেখানে প্যারামিটার হিসেবেObject[].classপাস করা হয়েছে। এর ফলে, মেথডটি যে কোনো টাইপের অ্যারে গ্রহণ করতে পারবে। - মেথডটি ইনভোক করার সময়
dataঅ্যারে প্রদান করা হয়েছে।
3. Generic Class এবং Method-এর প্যারামিটার টাইপ Access করা
Java Reflection API দ্বারা আপনি type parameters বা generic type parameters জানতে পারবেন, তবে, মনে রাখতে হবে যে, টাইপ-ইরেজার (type erasure) এর কারণে রানটাইমে তথ্য হারিয়ে যায়। তবে, আপনি Type ক্লাসের সাহায্যে টাইপ প্যারামিটার অ্যাক্সেস করতে পারেন।
উদাহরণ:
import java.lang.reflect.*;
class MyGenericClass<T> {
private T value;
public MyGenericClass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
public class ReflectionExample {
public static void main(String[] args) {
try {
// MyGenericClass<String> এর ক্লাস অবজেক্ট অ্যাক্সেস করা
Class<?> cls = MyGenericClass.class;
// টাইপ প্যারামিটারগুলো চেক করা
Type genericSuperclass = cls.getGenericSuperclass();
System.out.println("Generic superclass: " + genericSuperclass);
// কনস্ট্রাক্টর এবং মেথড খুঁজে বের করা
Constructor<?> constructor = cls.getConstructor(Object.class);
Method method = cls.getMethod("getValue");
// কনস্ট্রাক্টর এবং মেথড ইনভোক করা
Object obj = constructor.newInstance("Reflection with Generics");
System.out.println("Value from method: " + method.invoke(obj));
} catch (Exception e) {
e.printStackTrace();
}
}
}
ব্যাখ্যা:
- Generic Class:
MyGenericClass<T>তৈরি করা হয়েছে এবং এতেTটাইপ প্যারামিটার রয়েছে। - Reflection দিয়ে
getGenericSuperclass()ব্যবহার করে আপনি ক্লাসের জেনেরিক সুপারক্লাস দেখতে পারেন। getMethod()এবংgetConstructor()ব্যবহার করে জেনেরিক মেথড এবং কনস্ট্রাক্টর এক্সেস করা হয়েছে।
4. Generic Class এবং Method Access-এর Limitations
- Type Erasure: Java জেনেরিক টাইপগুলো রানটাইমে type erasure এর মাধ্যমে মুছে ফেলা হয়। এর মানে হলো,
Tবা জেনেরিক টাইপ রানটাইমে আর উপলব্ধ থাকে না, তাই আপনি রিফ্লেকশন ব্যবহার করে জেনেরিক টাইপের তথ্য অ্যাক্সেস করতে পারবেন না, শুধুমাত্র raw type বা non-generic type অ্যাক্সেস করতে পারবেন। - Generic Methods: জেনেরিক মেথডের প্যারামিটারও type erasure এর কারণে রানটাইমে পুরোপুরি মুছে ফেলা হয়। তবে, আপনি মেথডের parameter types বা return types অ্যাক্সেস করতে পারবেন।
Java Reflection API দিয়ে Generic Class এবং Generic Methods অ্যাক্সেস করার জন্য কিছু সীমাবদ্ধতা রয়েছে, কারণ জেনেরিক টাইপ type erasure এর মাধ্যমে রানটাইমে মুছে ফেলা হয়। তবে, আপনি ক্লাস এবং মেথডের raw types এবং তাদের প্যারামিটার এবং রিটার্ন টাইপ অ্যাক্সেস করতে পারেন। এটি জেনেরিক ক্লাস এবং মেথডের জন্য রানটাইমে ডাইনামিক আচরণ প্রয়োগ করার জন্য কার্যকর।
java.lang.reflect প্যাকেজে ParameterizedType এবং WildcardType দুটি ইন্টারফেস রয়েছে যা জাভার জেনেরিক টাইপ সিস্টেমের সঙ্গে সম্পর্কিত এবং এটি রিফ্লেকশন মাধ্যমে টাইপ ইনফরমেশন অ্যাক্সেস করতে ব্যবহৃত হয়।
১. ParameterizedType:
ParameterizedType ইন্টারফেসটি একটি জেনেরিক টাইপের প্যারামিটারাইজড রূপের টাইপ তথ্য ধারণ করে। এটি জেনেরিক টাইপ যেমন List<String>, Map<K, V>, ইত্যাদি বুঝতে সহায়তা করে। ParameterizedType ইন্টারফেসের মাধ্যমে আপনি কোন টাইপ প্যারামিটার ব্যবহৃত হয়েছে তা জানতে পারবেন।
ParameterizedType-এর ব্যবহার:
- আপনি
ParameterizedTypeব্যবহার করে একটি ক্লাস বা মেথডের টাইপ প্যারামিটার নিয়ে তথ্য সংগ্রহ করতে পারেন। - সাধারণভাবে এটি
Field,MethodবাConstructorঅবজেক্টেরgetGenericType()মেথড থেকে পাওয়া যায়।
উদাহরণ:
import java.lang.reflect.*;
import java.util.*;
public class ParameterizedTypeExample {
public static void main(String[] args) throws NoSuchFieldException {
// Example class with a generic field
class MyClass {
private List<String> list;
}
// Get the field "list" from MyClass
Field field = MyClass.class.getDeclaredField("list");
// Get the generic type of the field
Type fieldType = field.getGenericType();
if (fieldType instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) fieldType;
Type[] typeArguments = paramType.getActualTypeArguments();
// Print the type arguments of the generic type
for (Type type : typeArguments) {
System.out.println("Type argument: " + type.getTypeName());
}
}
}
}
Output:
Type argument: java.lang.String
ব্যাখ্যা:
- এখানে
MyClassএর একটি ফিল্ডlistরয়েছে, যা একটি প্যারামিটারাইজড টাইপList<String>। getGenericType()ব্যবহার করে, ফিল্ডটির টাইপ অবজেক্ট পাওয়া যায় এবং তার পরParameterizedTypeহিসেবে কাস্ট করে প্যারামিটারাইজড টাইপের বাস্তব ধরণ পাওয়া যায়।getActualTypeArguments()মেথডটি প্যারামিটারাইজড টাইপের আর্গুমেন্ট (যেমনStringএখানে) ফেরত দেয়।
২. WildcardType:
WildcardType ইন্টারফেসটি জেনেরিক টাইপে wildcards (যেমন ? extends T বা ? super T) ব্যবহৃত হলে এটি টাইপের তথ্য ধারণ করে। এই টাইপটি ? extends বা ? super এর মতো wildcards এর ব্যবহার ব্যাখ্যা করে।
WildcardType-এর ব্যবহার:
- Wildcard টাইপের মাধ্যমে আপনি এমন টাইপের তথ্য পেতে পারেন যা সাধারণত জেনেরিকের মধ্যে ব্যবহার করা হয়, কিন্তু প্রকারের প্যারামিটার নির্দিষ্ট নয়।
উদাহরণ:
import java.lang.reflect.*;
import java.util.*;
public class WildcardTypeExample {
public static void main(String[] args) throws NoSuchFieldException {
// Example class with a wildcard generic type
class MyClass {
private List<? extends Number> numbers;
}
// Get the field "numbers" from MyClass
Field field = MyClass.class.getDeclaredField("numbers");
// Get the generic type of the field
Type fieldType = field.getGenericType();
if (fieldType instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) fieldType;
Type[] upperBounds = wildcardType.getUpperBounds();
// Print the upper bounds of the wildcard
for (Type type : upperBounds) {
System.out.println("Upper bound: " + type.getTypeName());
}
}
}
}
Output:
Upper bound: java.lang.Number
ব্যাখ্যা:
- এখানে
MyClass-এর একটি ফিল্ডnumbersরয়েছে, যাList<? extends Number>টাইপে ডিফাইন করা আছে। ? extends Numberwildcard টাইপের মধ্যেNumberহলো upper bound।getUpperBounds()মেথডটিWildcardTypeএর upper bounds রিটার্ন করে, যা এই ক্ষেত্রেNumber।
WildcardType এর মূল বৈশিষ্ট্য:
getUpperBounds(): যেকোনো wildcard এর upper bounds (যেমন? extends T) দেয়।getLowerBounds(): যেকোনো wildcard এর lower bounds (যেমন? super T) দেয়।
সন্নিবেশ (Summary):
ParameterizedType: এটি ব্যবহৃত হয় যখন আপনি জেনেরিক টাইপের প্যারামিটারগুলি (যেমনList<String>) অ্যাক্সেস করতে চান।- উদাহরণ:
List<String>এর মধ্যেStringহচ্ছে প্যারামিটারাইজড টাইপের আর্গুমেন্ট।
- উদাহরণ:
WildcardType: এটি ব্যবহৃত হয় wildcard টাইপ (যেমন? extends Tবা? super T) এর তথ্য সংগ্রহ করতে।- উদাহরণ:
List<? extends Number>এর মধ্যেNumberহচ্ছে upper bound wildcard টাইপের।
- উদাহরণ:
ParameterizedType এবং WildcardType দুটি রিফ্লেকশন বৈশিষ্ট্য যা জেনেরিক টাইপ সিস্টেমের গুরুত্বপূর্ণ অংশ। এই দুটি ব্যবহার করে আপনি টাইপের প্যারামিটার এবং wildcard সম্পর্কে তথ্য সংগ্রহ করতে পারেন এবং টাইপ সেফ কোড তৈরি করতে সাহায্য করে।
Read more