जवाबों:
प्रत्येक वर्ग अन्य कक्षाओं को लोड करने के लिए अपने स्वयं के क्लास लोडर का उपयोग करेगा। तो अगर ClassA.class
संदर्भ ClassB.class
तो ClassB
की classloader की classpath पर होने की जरूरत है ClassA
, या उसके माता-पिता।
थ्रेड संदर्भ क्लास लोडर वर्तमान थ्रेड के लिए वर्तमान क्लास लोडर है। किसी ऑब्जेक्ट को किसी वर्ग से बनाया जा सकता है ClassLoaderC
और उसके बाद उसके स्वामित्व वाले थ्रेड को पास किया जा सकता है ClassLoaderD
। इस मामले में ऑब्जेक्ट को Thread.currentThread().getContextClassLoader()
सीधे उपयोग करने की आवश्यकता होती है यदि वह संसाधनों को लोड करना चाहता है जो अपने स्वयं के क्लास लोडर पर उपलब्ध नहीं हैं।
ClassA.class
संदर्भ ClassB.class
" कहने का क्या मतलब है ?
यह मूल प्रश्न का उत्तर नहीं देता है, लेकिन जैसा कि प्रश्न अत्यधिक रैंक और किसी भी ContextClassLoader
प्रश्न के लिए जुड़ा हुआ है , मुझे लगता है कि संबंधित प्रश्न का उत्तर देना महत्वपूर्ण है जब संदर्भ वर्ग लोडर का उपयोग किया जाना चाहिए। संक्षिप्त उत्तर: संदर्भ श्रेणी लोडर का उपयोग कभी न करें ! लेकिन इसे getClass().getClassLoader()
तब सेट करें जब आपको एक ऐसी विधि को कॉल करना होगा जो एक ClassLoader
पैरामीटर गायब है ।
जब एक वर्ग का कोड दूसरी कक्षा को लोड करने के लिए कहता है, तो उपयोग करने के लिए सही वर्ग लोडर कॉलर वर्ग (यानी getClass().getClassLoader()
) के रूप में एक ही वर्ग लोडर है । यह उस तरह से है जब चीजें 99.9% काम करती हैं क्योंकि यह वही है जो जेवीएम खुद करता है जब आप पहली बार एक नए वर्ग की आवृत्ति का निर्माण करते हैं, एक स्थैतिक विधि का उपयोग करते हैं, या एक स्थिर क्षेत्र का उपयोग करते हैं।
जब आप परावर्तन का उपयोग करके एक वर्ग बनाना चाहते हैं (जैसे कि जब विन्यास योग्य नामांकित कक्षा को डिस्क्राइबलाइज़ या लोड करना हो), तो जो पुस्तकालय प्रतिबिंब करता है, उसे हमेशा अनुप्रयोगClassLoader
से एक पैरामीटर के रूप में प्राप्त करके अनुप्रयोग को किस वर्ग लोडर का उपयोग करना चाहिए, यह पूछना चाहिए । आवेदन (जो सभी वर्गों को पता है कि निर्माण की आवश्यकता है) उसे पास करना चाहिए getClass().getClassLoader()
।
क्लास लोडर प्राप्त करने का कोई अन्य तरीका गलत है। यदि कोई लाइब्रेरी हैक का उपयोग करता है, जैसे कि Thread.getContextClassLoader()
, sun.misc.VM.latestUserDefinedLoader()
या sun.reflect.Reflection.getCallerClass()
यह एपीआई में कमी के कारण एक बग है। मूल रूप से, Thread.getContextClassLoader()
केवल इसलिए मौजूद है क्योंकि जिसने भी डिज़ाइन किया है ObjectInputStream
एपीआई ClassLoader
एक पैरामीटर के रूप में स्वीकार करना भूल गया , और इस गलती ने जावा समुदाय को आज तक परेशान किया है।
उस ने कहा, कई जेडीके कक्षाएं कुछ हैक का उपयोग करती हैं ताकि कुछ क्लास लोडर का उपयोग करने का अनुमान लगाया जा सके। कुछ एक का उपयोग करते हैं ContextClassLoader
(जो विफल रहता है जब आप एक साझा थ्रेड पूल पर अलग-अलग ऐप चलाते हैं, या जब आप छोड़ते हैं ContextClassLoader null
), तो कुछ स्टैक चलते हैं (जो तब विफल हो जाता है जब क्लास का डायरेक्ट कॉलर खुद एक पुस्तकालय होता है), कुछ सिस्टम क्लास लोडर का उपयोग करते हैं (जो ठीक है, जब तक इसे केवल कक्षाओं में उपयोग करने के लिए प्रलेखित किया जाता है CLASSPATH
) या बूटस्ट्रैप क्लास लोडर, और कुछ उपरोक्त तकनीकों के अप्रत्याशित संयोजन का उपयोग करते हैं (जो केवल चीजों को और अधिक भ्रमित करता है)। इससे दांतों का बहुत रोना और छींटाकशी हुई है।
इस तरह के एक एपीआई का उपयोग करते समय, सबसे पहले, क्लास लोडर को एक पैरामीटर के रूप में स्वीकार करने वाली विधि का अधिभार खोजने की कोशिश करें । अगर कोई समझदार तरीका नहीं है, तो ContextClassLoader
पहले एपीआई कॉल को सेट करने का प्रयास करें (और बाद में इसे रीसेट करें):
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
Javaworld.com पर एक लेख है जो अंतर बताता है => आपको किस क्लास-क्लास का उपयोग करना चाहिए
(1)
थ्रेड संदर्भ क्लास लोडर क्लास लोडिंग डेलिगेशन स्कीम के चारों ओर एक बैक डोर प्रदान करते हैं।
उदाहरण के लिए JNDI को लें: इसकी हिम्मत rt.jar में बूटस्ट्रैप कक्षाओं द्वारा कार्यान्वित की जाती है (J2SE 1.3 के साथ शुरू), लेकिन ये कोर JNDI कक्षाएं स्वतंत्र विक्रेताओं द्वारा कार्यान्वित JNDI प्रदाताओं को लोड कर सकती हैं और संभवतः एप्लिकेशन के -क्लासपैथ में तैनात की जा सकती हैं। यह परिदृश्य एक पैरेंट क्लास लोडर (इस मामले में प्राइमर्डियल एक) को अपने बच्चे के क्लास लोडर (उदाहरण के लिए सिस्टम एक) को दिखाई देने वाले एक वर्ग को लोड करने के लिए कहता है। सामान्य J2SE प्रतिनिधिमंडल काम नहीं करता है, और मुख्य JNDI वर्गों को थ्रेड संदर्भ लोडर का उपयोग करने के लिए वर्कअराउंड करना है, इस प्रकार प्रभावी रूप से उचित प्रतिनिधिमंडल के विपरीत दिशा में क्लास लोडर पदानुक्रम के माध्यम से "टनलिंग" करना है।
(2) एक ही स्रोत से:
यह भ्रम संभवतः कुछ समय के लिए जावा के साथ रहेगा। किसी भी प्रकार के डायनेमिक रिसोर्स लोडिंग के साथ J2SE API लें और यह अनुमान लगाने की कोशिश करें कि यह किस लोडिंग स्ट्रैटेजी का उपयोग करता है। यहाँ एक नमूना है:
- JNDI संदर्भ क्लास लोडर का उपयोग करता है
- Class.getResource () और Class.forName () वर्तमान क्लास लोडर का उपयोग करें
- JAXP संदर्भ क्लास लोडर (J2SE 1.4 के रूप में) का उपयोग करता है
- java.util.ResourceBundle कॉलर के करंट क्लास लोडर का उपयोग करता है
- Java.protocol.handler.pkgs सिस्टम प्रॉपर्टी के माध्यम से निर्दिष्ट URL प्रोटोकॉल हैंडलर को केवल बूटस्ट्रैप और सिस्टम क्लास लोडर में देखा जाता है
- जावा सीरियलाइज़ेशन एपीआई डिफ़ॉल्ट रूप से कॉलर के वर्तमान क्लास लोडर का उपयोग करता है
bootstrap
वर्ग लोडर को संदर्भ वर्ग लोडर के रूप में सेट नहीं किया जा रहा है, बल्कि इसके साथ स्थापित किया जा रहा चाइल्ड system
क्लासपथ क्लास लोडर है Thread
। JNDI
कक्षाएं तो उपयोग सुनिश्चित करते हुए कर रहे हैं Thread.currentThread().getContextClassLoader()
JNDI कार्यान्वयन कक्षाएं classpath पर उपलब्ध लोड करने के लिए।
@ डेविड रसेल जवाब में जोड़ते हुए, कई कक्षा लोडर द्वारा कक्षाएं भरी जा सकती हैं।
समझें कि क्लास लोडर कैसे काम करता है।
Javarevisited में javin paul ब्लॉग से:
ClassLoader
तीन सिद्धांतों का पालन करता है।
एक वर्ग जावा में लोड किया जाता है, जब इसकी आवश्यकता होती है। मान लें कि आपके पास एक विशिष्ट विशिष्ट वर्ग है, जिसे Abc.class कहा जाता है, इस वर्ग को लोड करने का पहला अनुरोध Application ClassLoader पर आएगा, जो इसके मूल एक्सटेंशन ClassLoader को सौंप देगा, जो आगे Primordial या बूटस्ट्रैप वर्ग लोडर को सौंपता है
बूटस्ट्रैप ClassLoader rt.jar से मानक JDK क्लास फ़ाइलों को लोड करने के लिए ज़िम्मेदार है और यह जावा में सभी क्लास लोडर का अभिभावक है। बूटस्ट्रैप क्लास लोडर का कोई अभिभावक नहीं है।
एक्सटेंशन क्लासलोडर अपने माता-पिता, बूटस्ट्रैप के लिए वर्ग लोडिंग अनुरोध को दर्शाता है और यदि असफल होता है, तो वर्ग प्रपत्र jre / lib / ext निर्देशिका या java.ext.dirs सिस्टम संपत्ति द्वारा इंगित किसी अन्य निर्देशिका को लोड करता है
सिस्टम या एप्लिकेशन क्लास लोडर और यह CLASSPATH पर्यावरण चर, -classpath या -cp कमांड लाइन विकल्प, JAR के अंदर मैनिफेस्ट फ़ाइल की क्लास-पाथ विशेषता से एप्लिकेशन विशिष्ट कक्षाओं को लोड करने के लिए जिम्मेदार है।
एप्लीकेशन क्लास लोडर एक्स्टेंशन क्लासलॉडर का एक बच्चा है और इसे sun.misc.Launcher$AppClassLoader
क्लास द्वारा कार्यान्वित किया जाता है ।
नोट: बूटस्ट्रैप क्लास लोडर को छोड़कर , जो मूल भाषा में ज्यादातर C में लागू होता है, सभी जावा क्लास लोडर का उपयोग करके लागू किया जाता है java.lang.ClassLoader
।
दृश्यता सिद्धांत के अनुसार, चाइल्ड क्लासलोडर पेरेंट क्लासलोडर द्वारा लोड की गई कक्षा को देख सकता है , लेकिन इसके विपरीत सच नहीं है।
इस सिद्धांत के अनुसार माता-पिता द्वारा लोड किए गए एक वर्ग को फिर से चाइल्ड क्लासलोडर द्वारा लोड नहीं किया जाना चाहिए
ClassB
के वर्गपथ पर होना चाहिए ? क्या यह लोडर को ओवरराइड करने के लिए संभव नहीं है , जैसे कि यह तब भी सफलतापूर्वक लोड हो सकता है, जब यह अपने वर्गपथ पर नहीं है?ClassA
ClassA
ClassA
loadClass()
ClassB
ClassB