यह एक AI अनुवादित पोस्ट है।
भाषा चुनें
durumis AI द्वारा संक्षेपित पाठ
- रिफ्लेक्शन एक एपीआई है जो रनटाइम पर क्लास जानकारी तक पहुँच प्रदान करके क्लास में हेरफेर करने की अनुमति देता है।
- रिफ्लेक्शन का उपयोग करके, क्लास के उदाहरण बनाए जा सकते हैं और फ़ील्ड और विधियों तक पहुँच प्राप्त की जा सकती है, जो एक्सेस मॉडिफायर से स्वतंत्र हैं। यह विशेष रूप से बड़े पैमाने पर विकास चरणों में, जैसे कि फ़्रेमवर्क में, गतिशील रूप से निर्भरता को प्रबंधित करने के लिए उपयोगी है।
- हालांकि, यह एन्कैप्सुलेशन को बाधित कर सकता है और प्रदर्शन को प्रभावित कर सकता है, इसलिए इसका उपयोग केवल तभी किया जाना चाहिए जब यह आवश्यक हो।
रिफ्लेक्शन क्या है?
रिफ्लेक्शन एक API है जो हीप क्षेत्र में लोड किए गए Class प्रकार की ऑब्जेक्ट के माध्यम से, वांछित वर्ग के इंस्टेंस को बनाने के लिए समर्थन प्रदान करता है, और इंस्टेंस के फील्ड और मेथड को एक्सेस कंट्रोलर से संबंधित किए बिना उपयोग करने के लिए समर्थन प्रदान करता है।
यहां, लोड किए गए वर्ग का अर्थ है कि JVM के क्लास लोडर ने क्लास फ़ाइल के लिए लोडिंग पूरी कर ली है, और फिर, Class प्रकार की ऑब्जेक्टजिसमें उस वर्ग की जानकारी होती है, उसे बनाया जाता है और मेमोरी के हीप क्षेत्र में संग्रहीत किया जाता है। ध्यान दें कि यह ऑब्जेक्ट new कीवर्ड का उपयोग करके बनाए गए ऑब्जेक्ट से अलग है। यदि आप इस Class प्रकार के ऑब्जेक्ट को नहीं समझते हैं, तो आप java.lang.class ऑब्जेक्ट के JDK दस्तावेज़ को देख सकते हैं।
उपयोग करने के तरीके
रिफ्लेक्शन का उपयोग करने से पहले, आपको हीप क्षेत्र में लोड किए गए Class प्रकार के ऑब्जेक्ट को पुनर्प्राप्त करने की आवश्यकता है। कुल तीन तरीके हैं।
- क्लास.class द्वारा पुनर्प्राप्त करें
- इंस्टेंस.getClass() द्वारा पुनर्प्राप्त करें
- Class.forName("क्लास नाम") द्वारा पुनर्प्राप्त करें
public class Member {
private String name;
protected int age;
public String hobby;
public Member() {
}
public Member(String name, int age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
public void speak(String message) {
System.out.println(message);
}
private void secret() {
System.out.println("पासवर्ड 1234 है।");
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class memberClass = Member.class;
System.out.println(System.identityHashCode(memberClass));
Member member = new Member("जयॉन", 23, "डारथ विकास");
Class extends Member> memberClass2 = member.getClass();
System.out.println(System.identityHashCode(memberClass2));
Class> memberClass3 = Class.forName("{पैकेज नाम}.Member");
System.out.println(System.identityHashCode(memberClass3));
}
}
// निष्पादन परिणाम
1740000325
1740000325
आप तीनों तरीकों से प्राप्त Class प्रकार के इंस्टेंस समान होने का पता लगा सकते हैं। कोई फर्क नहीं पड़ता कि आप किस विधि का उपयोग करते हैं, हैश मान समान है, इसलिए आप स्थिति के अनुसार इसका उपयोग कर सकते हैं।
अब, आप प्राप्त Class प्रकार का उपयोग करके उस वर्ग के इंस्टेंस बना सकते हैं, और इंस्टेंस के फील्ड और मेथड को एक्सेस कंट्रोलर से संबंधित किए बिना उपयोग कर सकते हैं। आइए पहले उस वर्ग के इंस्टेंस बनाएं।
public class Main {
public static void main(String[] args) throws Exception {
// Member के सभी कंस्ट्रक्टर आउटपुट करें
Member member = new Member();
Class extends Member> memberClass = member.getClass();
Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);
// Member के डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग करके इंस्टेंस बनाएँ
Constructor extends Member> constructor = memberClass.getConstructor();
Member member2 = constructor.newInstance();
System.out.println("member2 = " + member2);
// Member के अन्य कंस्ट्रक्टर का उपयोग करके इंस्टेंस बनाएँ
Constructor extends Member> fullConstructor =
memberClass.getConstructor(String.class, int.class, String.class);
Member member3 = fullConstructor.newInstance("जयॉन", 23, "डारथ विकास");
System.out.println("member3 = " + member3);
}
}
// निष्पादन परिणाम
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}
getConstructor() का उपयोग करके, आप कंस्ट्रक्टर प्राप्त कर सकते हैं, और newInstance() का उपयोग करके, आप गतिशील रूप से Member इंस्टेंस बना सकते हैं।
अंत में, आइए इंस्टेंस के फील्ड और मेथड को एक्सेस कंट्रोलर से संबंधित किए बिना एक्सेस करें और उनका उपयोग करें।
public class Main {
public static void main(String[] args) throws Exception {
Member member = new Member("जयॉन", 23, "डारथ विकास");
Class extends Member> memberClass = member.getClass();
// फ़ील्ड एक्सेस
Field[] fields = memberClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.get(member));
}
fields[0].set(member, "जयॉन2");
System.out.println(member);
// मेथड एक्सेस
Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
speakMethod.invoke(member, "रिफ्लेक्शन टेस्ट");
Method secretMethod = memberClass.getDeclaredMethod("secret");
secretMethod.setAccessible(true);
secretMethod.invoke(member);
}
}
// निष्पादन परिणाम
जयॉन
23
डारथ विकास
Member{name='जयॉन2', age=23, hobby='डारथ विकास'}
रिफ्लेक्शन टेस्ट
getDeclaredFileds() का उपयोग करके, आप क्लास के इंस्टेंस वेरिएबल को प्राप्त कर सकते हैं, get() का उपयोग करके, आप फ़ील्ड मान प्राप्त कर सकते हैं, और set() का उपयोग करके, आप फ़ील्ड मान को संशोधित कर सकते हैं। ध्यान दें कि जब आप private एक्सेस कंट्रोलर वाले फील्ड को एक्सेस करते हैं, तो आपको setAccessible() के तर्क में true पास करना होगा।
getDeclaredMethod() का उपयोग करके, आप मेथड भी प्राप्त कर सकते हैं। इस स्थिति में, आपको मेथड के नाम और पैरामीटर के प्रकार को तर्क के रूप में पास करना होगा। इसी तरह, जब आप private एक्सेस कंट्रोलर वाले मेथड को एक्सेस करते हैं, तो आपको setAccessible() के तर्क में true सेट करना होगा। अंत में, invoke() मेथड का उपयोग करके, आप रिफ्लेक्शन API द्वारा प्राप्त मेथड को कॉल कर सकते हैं।
लाभ और हानि
- लाभ
- यह रनटाइम के समय क्लास के इंस्टेंस को बनाने और एक्सेस कंट्रोलर से संबंधित किए बिना फील्ड और मेथड को एक्सेस करने की क्षमता प्रदान करता है, जिससे कार्य करने की लचीलापन मिलती है।
- हानि
- यह एनकैप्सुलेशन का उल्लंघन करता है।
- रनटाइम के समय इंस्टेंस बनाए जाते हैं, इसलिए आप कंपाइल टाइम पर उस प्रकार की जांच नहीं कर सकते।
- रनटाइम के समय इंस्टेंस बनाए जाते हैं, इसलिए विशिष्ट ऑपरेशन फ्लो का पता लगाना मुश्किल है।
- रिफ्लेक्शन का उपयोग करके एक्सेस करने की तुलना में फ़ील्ड और मेथड को सीधे एक्सेस करने का प्रदर्शन धीमा है। (यह सभी स्थितियों में धीमा नहीं है।)
इसका उपयोग क्यों करें
रिफ्लेक्शन API के माध्यम से, आप रनटाइम के दौरान क्लास जानकारी को एक्सेस कर सकते हैं और अपनी इच्छानुसार क्लास को मैनिपुलेट कर सकते हैं। यहां तक कि आप private एक्सेस कंट्रोलर द्वारा घोषित फील्ड और मेथड को भी संशोधित कर सकते हैं। यह एक ऐसी तकनीक की तरह लग सकता है जिसका उपयोग नहीं किया जाना चाहिए क्योंकि यह ऑब्जेक्ट-ओरिएंटेड डिजाइन में महत्वपूर्ण एनकैप्सुलेशन को तोड़ता है।
छोटे पैमाने पर कंसोल डेवलपमेंट में, डेवलपर कंपाइल टाइम पर प्रोग्राम में उपयोग किए जाने वाले ऑब्जेक्ट और निर्भरता संबंधों को पूरी तरह से समझ सकते हैं। हालांकि, फ्रेमवर्क जैसे बड़े पैमाने पर विकास में, बहुत सारे ऑब्जेक्ट और निर्भरता संबंधों को समझना मुश्किल हो जाता है। इस मामले में, रिफ्लेक्शन का उपयोग करके, आप गतिशील रूप से क्लास बना सकते हैं और निर्भरता संबंध बना सकते हैं।
उदाहरण के लिए, Spring के Bean फैक्ट्री को देखें, यह @Controller, @Service, @Repository जैसे एनोटेशन पर निर्भर करता है। Bean फैक्ट्री स्वचालित रूप से इन एनोटेशन वाले क्लास को बनाता है और उनका प्रबंधन करता है। डेवलपर ने Bean फैक्ट्री को इन क्लासों के बारे में नहीं बताया, लेकिन यह संभव है क्योंकि रिफ्लेक्शन का उपयोग किया जाता है। रनटाइम पर, यह इन एनोटेशन वाले क्लासों को ढूंढता है, और यदि ऐसा है, तो रिफ्लेक्शन का उपयोग करके, यह क्लास के इंस्टेंस बनाता है, आवश्यक फ़ील्ड इंजेक्ट करता है, और Bean फैक्ट्री में उन्हें संग्रहीत करता है।
बेशक, जैसा कि ऊपर उल्लेख किया गया है, एनकैप्सुलेशन को तोड़ा जाता है, इसलिए इसका उपयोग केवल तभी करना उचित है जब वास्तव में आवश्यक हो।