मुझे जावा में स्थिर निर्माणकर्ताओं की पूरी समझ नहीं थी। अगर इसकी अनुमति है, तो इसकी अनुमति क्यों है? आप किन परिदृश्यों में इसका उपयोग करेंगे? यह किस उद्देश्य की पूर्ति करेगा? क्या कोई मुझे एक सरल उदाहरण दे सकता है?
मुझे जावा में स्थिर निर्माणकर्ताओं की पूरी समझ नहीं थी। अगर इसकी अनुमति है, तो इसकी अनुमति क्यों है? आप किन परिदृश्यों में इसका उपयोग करेंगे? यह किस उद्देश्य की पूर्ति करेगा? क्या कोई मुझे एक सरल उदाहरण दे सकता है?
जवाबों:
कड़ाई से बोलने पर, जावा में स्थिर निर्माता नहीं हैं क्योंकि एक निर्माता, परिभाषा के अनुसार, स्थिर नहीं हो सकता है । जिसे आप संदर्भित कर रहे हैं उसे "स्थैतिक आरंभीकरण ब्लॉक" कहा जाता है। एक निर्माता का तात्पर्य है कि आप एक वस्तु का निर्माण कर रहे हैं। आपके पास एक वर्ग के लिए कंस्ट्रक्टर नहीं हो सकता है क्योंकि एक वर्ग स्वयं का उदाहरण नहीं है। यह बस एक वर्ग है। वह चीज जो "निर्माण करता है" वर्ग को कंपाइलर (या वर्चुअल मशीन कहा जाता है, जो "कंस्ट्रक्शंस" के अर्थ के आधार पर होता है), और यदि आप अन्य कोड के भीतर निर्माण कोड में आते हैं, तो आप कोड जनरेशन में प्रवेश कर रहे हैं, जो है एक पूरी तरह से अलग जानवर।
एक तरफ सभी नाइट-पिकिंग, एक क्लास के लिए जटिल स्टेटिक (या क्लास-लेवल) फ़ील्ड को इनिशियलाइज़ करने के लिए एक स्टैटिक इनिशियलाइज़ेशन ब्लॉक का उपयोग किया जाता है। आमतौर पर इनका उपयोग उन चीजों को शुरू करने के लिए किया जाता है, जिन्हें या तो एक लाइन में आरंभीकृत नहीं किया जा सकता है, या इसके लिए कुछ अन्य ऑब्जेक्ट की आवश्यकता होती है (जो स्टैटिक ब्लॉक लागू किया गया है या नहीं हो सकता है) पहले इनिशियलाइज़ किया जाता है।
मूल रूप से, कोई भी उन्हें वर्ग "अरे, इस मान को सेट करने के लिए चर ए, सेट करने के लिए कह सकता है, तब, एक बार ऐसा करने के बाद, बी को इनिशियलाइज़ करने के लिए ए के मूल्य का उपयोग करें।" चूँकि जावा को यह आवश्यक है कि मानक क्षेत्र आरंभीकरण को एक निर्माणकर्ता या विधि के भीतर, या एक निर्माता या विधि के कॉल के माध्यम से किया जाए (जब तक कि यह एक शाब्दिक नहीं है), ये जटिल, स्थिर वस्तुओं को शुरू करने के लिए एक सुविधाजनक तरीका हो सकते हैं।
स्टेटिक इनिशियलाइज़ेशन ब्लॉक्स की ज़रूरत सभी को अक्सर नहीं होती है, और आम तौर पर इनसे बचना चाहिए जब तक कि इनका वास्तविक उपयोग न हो। मुझे गलत मत समझो, उनके पास जावा में अपना स्थान है, लेकिन कई अन्य चीजों की तरह (जैसे कि ब्रेक, रिटर्न, स्विच, और गोटो स्टेटमेंट) वे आसानी से उपयोग किए जा सकते हैं, जिससे उनकी पठनीयता और कोड की स्थिरता कम हो जाती है -बस उनका इस्तेमाल किया जाता है।
स्थैतिक आरंभीकरण ब्लॉक का एक संक्षिप्त उदाहरण इस्तेमाल किया जा रहा है ( यहाँ पाया गया स्थैतिक आरंभीकरण ब्लॉकों की उत्कृष्ट व्याख्या के अनुसार ):
कोड:
public class StaticExample{
static {
System.out.println("This is first static block");
}
public StaticExample(){
System.out.println("This is constructor");
}
public static String staticString = "Static Variable";
static {
System.out.println("This is second static block and "
+ staticString);
}
public static void main(String[] args){
StaticExample statEx = new StaticExample();
StaticExample.staticMethod2();
}
static {
staticMethod();
System.out.println("This is third static block");
}
public static void staticMethod() {
System.out.println("This is static method");
}
public static void staticMethod2() {
System.out.println("This is static method2");
}
}
आउटपुट:
This is first static block
This is second static block and Static Variable
This is static method
This is third static block
This is constructor
This is static method2
कुछ उदाहरण वे सूचीबद्ध करते हैं जब स्थैतिक ब्लॉक उपयोगी हो सकते हैं:
स्थैतिक ब्लॉक (अन्य स्थितियों में) का उपयोग न करने के कुछ कारण:
this
कोई उदाहरण नहीं है क्योंकि आप कीवर्ड का उपयोग नहीं कर सकते ।मुझे ध्यान देना चाहिए: जबकि कुछ भाषाओं (जैसे सी #) में "कंस्ट्रक्टर" के लिए वाक्यविन्यास हो सकते हैं जो स्थिर हैं, उन "कंस्ट्रक्टर्स" उसी तरह से कार्य करते हैं जैसे स्थैतिक आरंभीकरण ब्लॉक जावा में करते हैं, और कई (स्वयं शामिल) द्वारा देखे जाते हैं एक ओओपी कंस्ट्रक्टर की मूल अवधारणा को देखते हुए भाषा में गलतफहमी ।
इसका उपयोग उन फ़ील्ड्स को इनिशियलाइज़ करने के लिए किया जाता है जो केवल इसे असाइन करने से कठिन है:
public class Example{
public final static Map<String, String> preFilledField;
static{
Map<String, String> tmp = new HashMap<>();
//fill map
preFilledField = Collections.unmodifiableMap(tmp);
}
}
मानचित्रण को प्रारंभ करना संभव नहीं है (जब तक कि आप अनाम उपवर्ग हैक का उपयोग न करें) इसलिए यह गारंटी देने का सबसे अच्छा तरीका है कि इसे पहले उपयोग से पहले भरा जाए।
जब आप इनिशियलाइज़ करते हैं तो आप चेक किए गए अपवादों को पकड़ने के लिए भी ऐसा कर सकते हैं
गुर्गदुर्गेन का जवाब शायद वही है जो आप खोज रहे हैं, लेकिन मैं सिर्फ कुछ अन्य बिंदुओं को जोड़ूंगा जो कभी-कभी उपेक्षित होते हैं जब कोई "स्थिर रचनाकार" चाहता है।
यदि आप एक स्थिर विधि चाहते हैं जो आपकी कक्षा का एक उदाहरण बनाता है, तो आप एक स्थिर विधि बना सकते हैं जो केवल कक्षा के निर्माता को आमंत्रित करती है।
public class Example
{
/** Static method to create an instance. */
public static Example build()
{ return new Example() ; }
/** A field of each instance. */
private String stuff ;
/** The class's actual constructor. */
public Example()
{ stuff = new String() ; }
public String getStuff()
{ return this.stuff ; }
/**
* Mutator for "stuff" property. By convention this returns "void"
* but you might want to return the object itself, to support the
* sort of chained invocations that are becoming trendy now. You'll
* see the stylistic benefits of chaining later in this example.
*/
public Example setStuff( String newStuff )
{
this.stuff = newStuff ;
return this ;
}
}
public class ExampleTest
{
public static void main( String[] args )
{
// The usual instance model.
Example first = new Example() ;
System.out.println( first.setStuff("stuff").getStuff() ) ;
// Using your static method to construct an instance:
Example second = Example.build() ;
System.out.println( second.setStuff("more stuff").getStuff() ) ;
// Chaining all the invocations at once:
System.out.println( Example.build().setStuff("even more stuff").getStuff() ) ;
}
}
यह उत्पादन का उत्पादन करता है:
stuff
more stuff
even more stuff
एक उदाहरण के निर्माण के लिए एक स्थिर विधि बनाने का दूसरा कारण वह मामला है जब आप यह सुनिश्चित करना चाहते हैं कि आपकी कक्षा का ठीक एक उदाहरण किसी भी समय मौजूद है; इसे सिंगलटन कहा जाता है । सम्मेलन द्वारा, इस तरह के एक वर्ग को एक स्थिर पद्धति प्रदान की जाएगी जिसे एक और एकमात्र उदाहरणgetInstance()
प्राप्त करने के लिए कहा जाता है जिसे "सिंगलटन" माना जाता है।
public class SingletonExample extends Example
{
// Note: This extends my previous example, which has a "stuff"
// property, and a trivial constructor.
/** The singleton instance, statically initialized as null. */
private static SingletonExample singleton = null ;
/**
* The static accessor for the singleton. If no instance exists,
* then it will be created; otherwise, the one that already exists
* will be returned.
*/
public static SingletonExample getInstance()
{
if( singleton == null )
singleton = new SingletonExample() ;
return singleton ;
}
}
public class SingletonExampleTest
{
public static void main( String[] args )
{
System.out.println( SingletonExample.getInstance().setStuff("stuff").getStuff() ) ;
// You could still create instances of this class normally if you want to.
SingletonExample otherstuff = new SingletonExample() ;
otherstuff.setStuff("other stuff") ;
// But watch what happens to this.
System.out.println( SingletonExample.getInstance().getStuff() ) ;
System.out.println( otherstuff.getStuff() ) ;
// Now we show what happens when you start modifying the singleton.
SingletonExample theoneandonly = SingletonExample.getInstance() ;
theoneandonly.setStuff("changed stuff") ;
System.out.println( SingletonExample.getInstance().getStuff() ) ;
}
}
यह निम्नलिखित उत्पादन करता है।
stuff
stuff
other stuff
changed stuff
सिंगलटन के लिए एक संदर्भ संग्रहीत करके, और फिर इसे संशोधित करके, getInstance()
उस संशोधित सिंगलटन को प्राप्त करने के लिए अगली कॉल ।
यह आपके आवेदन के लिए वैश्विक चर बनाने का एक तरीका के रूप में एकल का उपयोग करने के लिए आकर्षक है। कुछ संदर्भों में यह उपयोगी हो सकता है, लेकिन यह आपको परेशानी में भी डाल सकता है। विशेष रूप से मैं एंड्रॉइड ऐप विकसित करते समय एक दिलचस्प बग में भाग गया, जहां सिंगलटन के उदाहरण खो सकते हैं। एक गतिविधि से दूसरी में कूदना कभी-कभी JVM का नेतृत्व कर सकता है एक नए "क्लास लोडर" का उपयोग करना, जो उस सिंगलटन के बारे में नहीं जानता होगा जिसे पिछले वर्ग लोडर द्वारा सांख्यिकीय रूप से संग्रहीत किया गया था।
जबकि मैं समझता हूं कि ऐसे कई लोग हैं जो एक "स्थिर निर्माणकर्ता" की धारणा को एक मिथ्या नाम के रूप में देखते हैं, मुझे विश्वास नहीं है कि मामला होना चाहिए। मुद्दा दोनों वर्गों और उनके उदाहरण वस्तुओं के निर्माण की प्रक्रिया में है । यह अन्य थ्रेड्स में कहा गया है कि क्लास का निर्माण कंपाइलर का काम है। जावा में भी, यह केवल आधा सच है।
कंपाइलर प्रत्येक वर्ग परिभाषा के लिए एक पाड़ का निर्माण करता है। मचान में वर्ग के बारे में मेटाडेटा शामिल है और निर्माण के समय उनके पास क्या उदाहरण हैं। यदि एक वर्ग एक क्षेत्र को परिभाषित करता है जिसे एक निरंतर आदिम मान सौंपा गया है, तो वह मान संकलक द्वारा पाड़ में शामिल किया जाता है। किसी अन्य मान प्रकार को असाइन किए जाने के लिए, कंपाइलर एक इनिशियलाइज़ेशन रुटीन बनाता है, जिसे फर्स्ट क्लास इंस्टेंस के निर्माण से पहले 1 बार चलाया जाता है, जो उचित मानों के साथ पाड़ को अपडेट करता है। यह अद्यतन संकलक द्वारा नहीं किया जा सकता है।
चूंकि मचान के लिए यह एक बार का अद्यतन अक्सर उदाहरण के निर्माणकर्ताओं के उचित कामकाज के लिए एक महत्वपूर्ण शर्त है, इसलिए इसे एक प्रकार का निर्माणकर्ता कहना भी उचित है। यही कारण है कि आम ओओ भाषाओं में जो अवधारणा का समर्थन करते हैं, इसे एक स्थिर रचनाकार कहा जाता है। जावा में स्टैटिक इनिशियलाइज़ेशन ब्लॉक्स के पीछे का कॉन्सेप्ट इस सिचुएशन के मुताबिक रखने के लिए सिमेंटिक चेंज से थोड़ा ज्यादा है कि जावा प्रोग्रामर सिस्टम और इंप्लायमेंट एग्नोस्टिक दोनों होने चाहिए।
जैसा कि अन्य उत्तरों ने कहा है, आप स्थैतिक तरीके लिख सकते हैं जो एक वस्तु का निर्माण करते हैं। यह जावा (और कई अन्य भाषाओं में नामित कंस्ट्रक्टरों की कमी को पूरा करता है। डेल्फी कंस्ट्रक्टर्स नाम का समर्थन करता है)। आप मापदंडों के प्रकार और क्रम के साथ खेल सकते हैं लेकिन इससे अस्पष्ट और नाजुक कोड हो सकता है।
उदाहरण के लिए, हम एक ऐसे परिदृश्य का आविष्कार कर सकते हैं जहाँ आपकी वस्तु का निर्माण XML स्ट्रिंग या JSON स्ट्रिंग से किया जा सकता है। आप इस तरह के तरीके लिख सकते हैं:
static MyObject createFromXml(String xml);
static MyObject createFromJson(String json);
मैंने इसका उपयोग कभी-कभी नामांकित प्रारंभिक विधियों के साथ एक पैरामीटर रहित निर्माता के विकल्प के रूप में किया है:
MyObject myObject = new MyObject();
myObject.loadXml(xml).
आप अपनी कक्षा के अंदर बिल्डर पैटर्न को लागू करने के रूप में एक स्थैतिक निर्माण विधि को देख सकते हैं।
आप वर्ग गुणों (जावा में स्थिर) को इनिशियलाइज़ करने के लिए एक क्लास लेवल कंस्ट्रक्टर की तरह "स्टैटिक" सेक्शन देख सकते हैं। "सामान्य" कंस्ट्रक्टर के समान ही इसका उपयोग उदाहरण स्तर के गुणों को शुरू करने के लिए किया जाता है।