2011-12-01 8 views
38

के बीच अंतर हाल ही में कुछ कोड आया जो मुझे सोचने लगा।जावा: कक्षा .forName और ClassLoader.loadClass

Class theClass = Class.forName("SomeImpl"); 
SomeImpl impl = (SomeImpl)theClass.newInstance(); 

और:

Class theClass = ClassLoader.loadClass("SomeImpl"); 
SomeImpl impl = (SomeImpl)theClass.newInstance(); 

वे पर्याय बन गया है के बीच क्या अंतर है? क्या कुछ परिस्थितियों में दूसरे के लिए बेहतर है? इन दो तरीकों का उपयोग करने के लिए क्या करें और क्या नहीं है?

अग्रिम धन्यवाद।

+0

व्यक्तिगत रूप से मैं अपने कोड में शाब्दिक तारों का उपयोग न करने का प्रयास करता हूं ... हार्ड-कोडित शाब्दिक के बजाय 'SomeImpl.class.getSimpleName()' लिखने पर विचार करें (कक्षा का नाम बदलने पर सिरदर्द बचाता है)। – Yuval

+8

@ युवाल: आमतौर पर मैं आपसे सहमत हूं, लेकिन 'class.forName()' पूरे बिंदु * के मामले में यह है कि आप इसे एक स्ट्रिंग पास करते हैं। यदि आपके पास 'कक्षा ' उदाहरण है जो आसपास झूठ बोल रहा है, तो आपको 'class.forName()' को कॉल करने की आवश्यकता नहीं है। और यदि आप 'SomeImpl.class' लिख सकते हैं तो आप प्रतिबिंब का उपयोग करने के बजाय' नया कुछ Impl() 'लिख सकते हैं। –

+2

@ युवाल, गतिशील वर्ग लोडिंग जावा में एक मुख्य विशेषता है और कक्षा के बजाय स्ट्रिंग के डब्ल्यू/उपयोग करने के लिए कुछ भी नहीं है। [डी प्राइडन पहले से ही कवर करता है] – bestsss

उत्तर

18

कक्षा .forName() हमेशा कॉलर के क्लासलोडर का उपयोग करेगा, जबकि ClassLoader.loadClass() एक अलग क्लासलोडर निर्दिष्ट कर सकता है। मेरा मानना ​​है कि क्लास.forनाम लोडेड क्लास को भी शुरू करता है, जबकि क्लासलोडर.लोड क्लास() दृष्टिकोण तुरंत ऐसा नहीं करता है (इसे तब तक शुरू नहीं किया जाता जब तक कि इसे पहली बार उपयोग नहीं किया जाता)।

प्रारंभिक व्यवहार के मेरे सारांश की पुष्टि करने के लिए बस यह आलेख मिला। यह इस तरह दिखता है जानकारी का सबसे आप देख रहे हैं की है:

http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html

यह प्रयोग बहुत अच्छा है, हालांकि मैं इससे पहले कि यह उपयोग नहीं किया है:

Class.forName(String, boolean, ClassLoader) 

यह करने की अनुमति देता क्लासलोडर निर्दिष्ट करें और बुलियन पैरामीटर यह निर्धारित करता है कि कक्षा लोड होने पर या प्रारंभ होने पर प्रारंभ किया जाना चाहिए या नहीं।

+1

यदि आप एक प्रदान नहीं करते हैं तो यह केवल कॉलर के क्लासलोडर का उपयोग करेगा। उसी लेख से: "... यदि कक्षा को लोड करने के लिए एक विशिष्ट लोडर चुनना आपके डिजाइन के लिए महत्वपूर्ण है, तो आपको 'क्लासलोडर' का उपयोग करना चाहिए।loadClass() '** या के लिए तीन पैरामीटर संस्करण() ** जावा 2 प्लेटफार्म, मानक संस्करण (जे 2 एसई) में जोड़ा गया: 'कक्षा .forName (स्ट्रिंग, बूलियन, क्लासलोडर)'। – phs

10

शॉन का जवाब कम या ज्यादा सही कुछ चूक/छोटी त्रुटियों को छोड़कर है:

  • Class.forName सहयोगियों वर्ग डब्ल्यू/classloader (चाहे किसी भी अन्य माता-पिता यह असली के लिए लोड करता है, तो), इसलिए ClassLoader.findLoadedClass है सफल अगली बार । यह एक बहुत ही महत्वपूर्ण बिंदु है, अधिकांश क्लासलोडर Class c = findLoadedClass(name); if (c!=null) return c; को पूरे खोज/लुक अप पार्ट को छोड़कर पहले बयान के रूप में प्रयास करेगा। क्लासलोडर.लोड को कॉल करना सीधे लोड किए गए लोगों को कक्षा नहीं जोड़ देगा।

क्लासलोडर के ग्राफ समान संरचना के माध्यम से लोड होने पर मामले के प्रभाव पड़ते हैं, यानी माता-पिता का उपयोग केवल पहले देखने के लिए नहीं करते हैं। वर्ग के

  • प्रारंभ ऐसा डब्ल्यू/कोड classloader की loadClass में किया जाता है: if (resolve) resolveClass(c); और classloader वास्तव में इसे हल करने के लिए यह, की तरह unrecommended लेकिन संभव लगता है छोड़ सकते हैं।

इन दो तरीकों का उपयोग करने के लिए क्या करें और क्या नहीं है?

जब तक आपके पास बहुत मजबूत विचार नहीं है कि आप ClassLoader.loadClass(String) क्यों चाहते हैं, तो इसका सीधे उपयोग न करें। अन्य सभी मामलों में, हमेशा Class.forName(name, true, classLoader) पर भरोसा करें।

कुल मिलाकर कक्षा लोड हो रहा है एक कला के बगल में है और यह एक साधारण जवाब में शामिल नहीं किया जा सकता है (कला भाग के बारे में मज़ाक नहीं कर)

3

जब आप Class.forName("SomeImpl") उपयोग करते हैं, आप वर्तमान classloader के माध्यम से वर्ग प्राप्त कर रहे हैं का उपयोग (यानी उस वर्ग का लोडर जिसे आप विधि कॉल कर रहे हैं)।यह कक्षा भी initialize कक्षा होगी। यह प्रभावी रूप से Class.forName("SomeImpl", true, currentLoader) पर कॉल करने जैसा ही है जहां currentLoader कॉलर का क्लासलोडर होगा। विवरण here देखें।

दूसरी विधि को पहले क्लासलोडर को चुना जाना आवश्यक है। ClassLoader.loadClass("SomeImpl") की तरह इसे न लिखें क्योंकि यह एक स्थैतिक विधि नहीं है। आप की तरह

final ClassLoader cl = this.getClass().getClassLoader(); 
Class theClass = cl.loadClass("SomeImpl"); 

मन कुछ है कि classloader की उपवर्गों loadClass बजाय findClass विधि ओवरराइड करना चाहिए की आवश्यकता होगी। यह (संरक्षित) विधि loadClass("SomeImpl", false) पर कॉल करने जैसा ही है, जहां दूसरा तर्क इंगित करता है कि लिंकिंग किया जाना चाहिए या नहीं।

अधिक सूक्ष्म अंतर कर रहे हैं ... loadClass विधि एक द्विआधारी वर्ग के नाम के रूप में, जावा भाषा विशिष्टता द्वारा निर्दिष्ट जबकि forName भी आदिम प्रकार या सरणी वर्गों के प्रतिनिधि स्ट्रिंग्स के साथ इस्तेमाल किया जा सकता की उम्मीद है।

ओवरल, Class.forName का उपयोग करना सबसे अच्छा है, यदि आवश्यक हो तो एक विशिष्ट क्लासलोडर निर्दिष्ट करें और क्या इसे इंटिलाइज्ड किया जाना चाहिए या नहीं, तो कार्यान्वयन बाकी को समझने दें। क्लासलोडर्स का उपयोग सीधे जार या क्लासपाथ पर संसाधन ढूंढने के लिए अच्छा होता है।

1

इस लाइन संकलन नहीं होगा:

Class theClass = ClassLoader.loadClass("SomeImpl"); 

क्योंकि loadClass classloader की एक स्थिर तरीका नहीं है।

इस समस्या को दूर करने के लिए, 3 संभव तरीकों में से एक में इस प्रकार एक classloader वस्तु बनाने:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 
ClassLoader classLoader = Main.class.getClassLoader();  // Assuming in class Main 
ClassLoader classLoader = getClass().getClassLoader();  // works in any class 

तो फोन:

Class theClass = classLoader.loadClass("SomeImpl"); 

-dbednar

0

loadClass() विधि 'कर सकते हैं टी static एक के रूप में बुलाया जा सकता है। ClassLoader के लिए उप-वर्ग बनाएं और संचालन करने के लिए कुछ अतिरिक्त विधियां बनाएं। ClassLoader कक्षा को बढ़ाकर अपना खुद का वर्ग लोडर बना सकते हैं। कार्यात्मक दोनों तरीकों में समान हैं।

संबंधित मुद्दे