प्रश्न और दायरा
Java 25 में अपग्रेड करने के बाद, एक टीम छोटी यूटिलिटीज के लिए कॉम्पैक्ट सोर्स फाइलों का उपयोग करना चाहती है। एंट्री-पॉइंट चयन, इम्प्लिसिट रूप से घोषित क्लास के मेंबर्स, ऑटोमैटिक-इम्पोर्ट सीमाओं को समझाएं, और बताएं कि आप प्रोडक्शन में इस फीचर को अपनाने का निर्णय कैसे लेंगे।
JEP 512 प्रिव्यू रिलीज के बाद Compact Source Files और Instance Main Methods को अंतिम रूप देता है। एक फ़ाइल टॉप-लेवल क्लास डिक्लेरेशन को छोड़ सकती है; टॉप-लेवल फ़ील्ड्स, मेथड्स और नेस्टेड डिक्लेरेशन एक इम्प्लिसिट रूप से घोषित क्लास के मेंबर्स बन जाते हैं, जबकि लॉन्चर अभी भी एक लॉन्च करने योग्य main मेथड खोजने के लिए एक निश्चित प्रोटोकॉल का पालन करता है।
इंटरव्यूअर क्या जांच रहा है
लैंग्वेज शुगर के पीछे वास्तविक क्लास मॉडल, बिना-आर्ग्युमेंट और ऐरे-आर्ग्युमेंट एंट्री पॉइंट्स के बीच अंतर, java.base ऑन-डिमांड इम्पोर्ट्स और IO सीमा, कंपाइल और रन कमांड्स, डॉक्यूमेंटेशन और डीबगिंग सीमाएं, और एक क्रमिक अपनाने की रणनीति को कवर करें।
30-सेकंड का उत्तर
“मैं इसे सिंगल-फ़ाइल स्क्रिप्ट्स, शिक्षण उदाहरणों और वन-ऑफ टूल्स के लिए बॉयलरप्लेट में कमी के रूप में रखूँगा। कंपाइलर इम्प्लिसिट रूप से Object को एक्सटेंड करने वाली एक क्लास घोषित करता है; टॉप-लेवल मेंबर्स इसके मेंबर्स बन जाते हैं। लॉन्चर पहले एक एक्सेसिबल void main(String[]) चुनता है और अन्यथा एक एक्सेसिबल void main(); डिफ़ॉल्ट कंस्ट्रक्टर चलने के बाद एक इंस्टेंस एंट्री पॉइंट को इन्वोक किया जाता है। Java 25, java.base द्वारा एक्सपोर्ट किए गए पब्लिक टॉप-लेवल टाइप्स को ऑन-डिमांड इम्पोर्ट करता है, लेकिन IO स्टैटिक मेथड्स इम्प्लिसिट रूप से इम्पोर्ट नहीं होते हैं। मैं पब्लिक लाइब्रेरीज़ और जटिल सर्विसेज के लिए एक्सप्लिसिट क्लासेस रखूँगा, पहले टारगेट JDK, बिल्ड टूल्स और डॉक्यूमेंटेशन पाइपलाइन को वैलिडेट करूँगा।”
चरण-दर-चरण समाधान
चरण 1: इम्प्लिसिट रूप से घोषित क्लास की पहचान करें
बिना एनक्लोजिंग क्लास डिक्लेरेशन वाली सोर्स फ़ाइल इम्प्लिसिट रूप से एक क्लास घोषित करती है। यह Object को एक्सटेंड करती है, इसमें एक डिफ़ॉल्ट नो-आर्ग्युमेंट कंस्ट्रक्टर होता है, और इसे होस्ट द्वारा चुना गया एक नाम मिलता है जिसे अन्य सोर्स कोड सीधे संदर्भित नहीं कर सकता है। फ़ाइल में फ़ील्ड्स, मेथड्स और नेस्टेड डिक्लेरेशन उस क्लास के मेंबर्स बन जाते हैं।
चरण 2: लॉन्च करने योग्य एंट्री पॉइंट निर्धारित करें
लॉन्चर पहले String-ऐरे पैरामीटर वाले एक एक्सेसिबल void main को खोजता है। यदि कोई मौजूद नहीं है, तो यह बिना किसी पैरामीटर वाले एक्सेसिबल void main को खोजता है। जब चयनित मेथड एक इंस्टेंस मेथड होता है, तो लॉन्चर इसे इन्वोक करने से पहले इम्प्लिसिट क्लास का एक इंस्टेंस बनाता है।
void main(String[] args) {
IO.println("hello " + args[0]);
}चरण 3: ऑटोमैटिक इम्पोर्ट्स को समझें
एक कॉम्पैक्ट सोर्स फ़ाइल इस तरह काम करती है जैसे कि वह java.base द्वारा एक्सपोर्ट किए गए पब्लिक टॉप-लेवल टाइप्स को ऑन-डिमांड इम्पोर्ट करती है, इसलिए Map और Stream जैसे टाइप्स को आमतौर पर किसी एक्सप्लिसिट इम्पोर्ट की आवश्यकता नहीं होती है। यह मनमाने मॉड्यूल्स को इम्पोर्ट नहीं करता है, और IO स्टैटिक मेथड्स इम्प्लिसिट रूप से इम्पोर्ट नहीं होते हैं; IO.println को कॉल करें या एक एक्सप्लिसिट स्टैटिक इम्पोर्ट जोड़ें।
चरण 4: रन और कंपाइल मोड्स में अंतर करें
आप java Hello.java चला सकते हैं, जिससे लॉन्चर फ़ाइल को कंपाइल और निष्पादित कर सकता है, या javac Hello.java के बाद जनरेट की गई क्लास चला सकते हैं। प्रत्यक्ष सोर्स निष्पादन छोटी स्क्रिप्ट्स के लिए सुविधाजनक है; दोहराए जाने योग्य बिल्ड, कैशिंग और रिलीज पाइपलाइनों को अभी भी एक ज्ञात आउटपुट डायरेक्टरी में स्पष्ट रूप से कंपाइल करना चाहिए।
चरण 5: स्टेट और लाइफसाइकिल का विश्लेषण करें
टॉप-लेवल फ़ील्ड्स इम्प्लिसिट क्लास के फ़ील्ड्स बन जाते हैं, इसलिए एक इंस्टेंस main इंस्टेंस स्टेट को पढ़ सकता है। लॉन्चर डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग करता है, इसलिए बाहरी कंस्ट्रक्टर-आर्ग्युमेंट इंजेक्शन इस प्रोटोकॉल का हिस्सा नहीं है। जटिल इनिशियलाइज़ेशन, मल्टीपल एंट्री पॉइंट्स या एक एक्सप्लिसिट लाइफसाइकिल की समीक्षा एक नामित क्लास में करना आसान होता है।
चरण 6: टूलिंग सीमाओं का मूल्यांकन करें
इम्प्लिसिट रूप से घोषित क्लास के पास अन्य क्लासेस द्वारा संदर्भित किए जाने के लिए कोई स्थिर सोर्स-लेवल नाम नहीं होता है, और javadoc इसके लिए पारंपरिक API जनरेट नहीं कर सकता है। IDEs, स्टैटिक एनालाइजर्स, कवरेज टूल्स और डीबगर्स अलग-अलग वर्ज़न पर इस सिंटैक्स का समर्थन कर सकते हैं; टारगेट JDK और बिल्ड प्लगइन्स को एक साथ वैलिडेट करें।
चरण 7: माइग्रेशन और रोलबैक डिज़ाइन करें
स्क्रिप्ट्स या शिक्षण उदाहरणों को पहले एक अलग डायरेक्टरी में ले जाएं और रोलबैक के रूप में एक एक्सप्लिसिट-क्लास वर्ज़न रखें। CI में Java 25 को पिन करें, जांचें कि java और javac वर्ज़न मेल खाते हैं, और सत्यापित करें कि पैकेजिंग, लॉग्स, अपवाद ट्रेस और कंटेनर कमांड्स इम्प्लीमेंटेशन क्लास के नाम पर निर्भर नहीं हैं।
चरण 8: अपनाने की सीमा को परिभाषित करें
अपनाना इस बात पर निर्भर करता है कि कोड को एक स्थिर API, डिपेंडेंसी इंजेक्शन, देखने योग्य एंट्री पॉइंट्स या क्रॉस-मॉड्यूल पुनर्चक्रण की आवश्यकता है या नहीं। कम सेरेमनी के साथ एक सिंगल-फ़ाइल ऑपरेशंस टूल अधिक स्पष्ट हो सकता है; एक शेयर्ड लाइब्रेरी, लंबे समय तक चलने वाली सर्विस या डॉक्यूमेंटेड API को आमतौर पर एक एक्सप्लिसिट क्लास से लाभ होता है।
ट्रेड-ऑफ और सीमाएं
सरलता या खोजने की क्षमता
कॉम्पैक्ट फ़ाइलें शुरुआती उदाहरणों को उनके उद्देश्य के करीब रखती हैं, लेकिन इम्प्लिसिट नाम और इम्पोर्ट नियम आवश्यक टूलिंग ज्ञान की मात्रा को बढ़ाते हैं। इस फीचर को कम-कपलिंग वाली डायरेक्टरीज़ तक सीमित रखें और उस सीमा को कोडिंग मानक में डॉक्यूमेंट करें।
इंस्टेंस main या स्टैटिक main
एक इंस्टेंस main सीधे फ़ील्ड्स और इंस्टेंस मेथड्स का उपयोग कर सकता है, जो स्टेटफुल प्रदर्शनों के लिए उपयुक्त है। एक स्टैटिक main पारंपरिक Java लॉन्च पाथ का अधिक बारीकी से पालन करता है। किसी भी तरह से, एंट्री सिग्नेचर को स्पष्ट रखें ताकि लॉन्चर कई उम्मीदवारों की रिपोर्ट न करे।
ऑटोमैटिक इम्पोर्ट्स या एक्सप्लिसिट इम्पोर्ट्स
java.base ऑन-डिमांड नियम शिक्षण कोड से इम्पोर्ट्स को हटा देता है, लेकिन अन्य मॉड्यूल्स के टाइप्स को अभी भी एक एक्सप्लिसिट मॉड्यूल या सामान्य इम्पोर्ट की आवश्यकता होती है। शेयर्ड प्रोडक्शन कोड को इम्प्लिसिट नियमों को याद रखने के लिए पाठकों पर भरोसा करने के बजाय स्पष्ट रूप से डिपेंडेंसीज़ बतानी चाहिए।
विफलता अभ्यास और विकास
कई main उम्मीदवार
नो-आर्ग्युमेंट और String-ऐरे दोनों एंट्री पॉइंट्स जोड़ें और सत्यापित करें कि ऐरे फॉर्म जीतता है। रिटर्न टाइप या विजिबिलिटी बदलें और लॉन्चर के एरर और फॉलबैक व्यवहार को सत्यापित करें।
इम्प्लिसिट क्लास के नाम पर निर्भर होना
एक दूसरी सोर्स फ़ाइल से जनरेट किए गए क्लास नाम को संदर्भित करवाएं, पुष्टि करें कि कंपाइलेशन विफल हो जाता है, और शेयर्ड लॉजिक को एक स्पष्ट रूप से नामित क्लास में ले जाएं।
असंगत टूलचेन्स
एक ही फ़ाइल को पुराने JDK और Java 25 के साथ कंपाइल करें। CI को रनटाइम तक सिंटैक्स विफलता को टालने के बजाय लैंग्वेज-लेवल बेमेल होने पर तुरंत विफल होना चाहिए।
सामान्य गलतियां और फॉलो-अप
गलती 1: यह मान लेना कि फ़ाइल में कोई क्लास नहीं है
फॉलो-अप: टॉप-लेवल मेथड्स और फ़ील्ड्स कहाँ रहते हैं? वे कंपाइलर द्वारा जनरेट की गई इम्प्लिसिट क्लास के मेंबर्स हैं और फिर भी मेंबर और इंस्टेंस-लाइफसाइकिल नियमों का पालन करते हैं।
गलती 2: यह मान लेना कि हर इम्पोर्ट ऑटोमैटिक है
फॉलो-अप: IO.println को क्लास का नाम क्यों देना चाहिए? IO स्टैटिक मेथड्स इम्प्लिसिट रूप से इम्पोर्ट नहीं होते हैं; java.base पब्लिक टॉप-लेवल टाइप्स ऑन-डिमांड इम्पोर्ट किए जाते हैं।
गलती 3: स्क्रिप्ट सिंटैक्स को एक स्थिर API मानना
फॉलो-अप: क्या कोई अन्य मॉड्यूल इम्प्लिसिट क्लास पर निर्भर हो सकता है? यह इम्प्लीमेंटेशन नाम पर भरोसा नहीं कर सकता; पुन: प्रयोज्य APIs स्पष्ट रूप से नामित क्लासेस में होती हैं।
गहरे फॉलो-अप और मॉडल उत्तर
इंस्टेंस main को डिफ़ॉल्ट कंस्ट्रक्टर की आवश्यकता क्यों होती है?
एक इंस्टेंस एंट्री पॉइंट चुनने के बाद, लॉन्चर इम्प्लिसिट रूप से घोषित क्लास का निर्माण करता है और फिर मेथड को इन्वोक करता है। कॉम्पैक्ट फाइलों में कोई कंस्ट्रक्टर-आर्ग्युमेंट प्रोटोकॉल नहीं होता है, इसलिए बाहरी इंजेक्शन के लिए एक एक्सप्लिसिट क्लास की आवश्यकता होती है।
प्रत्यक्ष सोर्स निष्पादन पहले कंपाइल करने से कैसे भिन्न है?
प्रत्यक्ष निष्पादन java लॉन्चर को अस्थायी रूप से कंपाइल करने और सोर्स चलाने की अनुमति देता है, जो छोटी स्क्रिप्ट्स के लिए उपयुक्त है। javac के साथ पहले कंपाइल करना CI और रिलीज सिस्टम को स्थिर आर्टिफैक्ट्स, कैशिंग और डायग्नोस्टिक्स देता है।
आपको एक एक्सप्लिसिट क्लास पर कब वापस लौटना चाहिए?
एक एक्सप्लिसिट नामित क्लास का उपयोग करें जब आपको एक स्थिर टाइप नाम, पब्लिक API, javadoc, डिपेंडेंसी इंजेक्शन, मल्टीपल कंस्ट्रक्शन पाथ्स, या क्रॉस-मॉड्यूल पुनर्चक्रण की आवश्यकता हो, भले ही सिंगल-फ़ाइल फॉर्म में अधिक बॉयलरप्लेट हो।