जावा में आदिम बनाम वर्ग का उपयोग कब करें?


54

मैं देखता हूं कि जावा में बूलियन (वर्ग) बनाम बूलियन (आदिम) है। इसी तरह, एक पूर्णांक (वर्ग) बनाम इंट (आदिम) है। कक्षा के बनाम आदिम संस्करण का उपयोग करने पर सबसे अच्छा अभ्यास क्या है? क्या मुझे मूल रूप से हमेशा वर्ग संस्करण का उपयोग करना चाहिए जब तक कि मेरे पास विशिष्ट (प्रदर्शन?) कारण नहीं है? प्रत्येक का उपयोग करने के लिए सबसे आम, स्वीकृत तरीका क्या है?



मेरे दिमाग में वे कक्षाएं नहीं हैं, वे बक्से हैं। वे केवल इसलिए हैं ताकि आप उन प्राइमिटिव्स का उपयोग कर सकें जहां ऑब्जेक्ट्स की आवश्यकता होती है, अर्थात संग्रह में। आप दो इंटेगर नहीं जोड़ सकते (आप दिखावा कर सकते हैं लेकिन वास्तव में जावा ऑटो बॉक्सिंग है। आपके लिए मानों को अनबॉक्स करना)।
स्टोनमेटल

जवाबों:


47

प्रभावी जावा के आइटम 5 में, यहोशू बलोच कहते हैं

पाठ स्पष्ट है: बॉक्सिंग की प्राथमिकताओं के लिए प्राथमिकताओं को प्राथमिकता दें, और अनजाने ऑटोबॉक्सिंग के लिए देखें

वर्गों के लिए एक अच्छा उपयोग तब होता है जब उन्हें सामान्य प्रकारों के रूप में उपयोग किया जाता है (संग्रह वर्गों, जैसे सूचियों और नक्शों सहित) या जब आप उन्हें बिना किसी अन्य प्रकार के रूपांतरण के कास्टिंग के लिए बदलना चाहते हैं (उदाहरण के लिए Integerकक्षा में विधियाँ हैं doubleValue()या byteValue()

संपादित करें: यहोशू बलोच का कारण है:

// Hideously slow program! Can you spot the object creation?
public static void main(String[] args) {
    Long sum = 0L;
    for (long i = 0; i < Integer.MAX_VALUE; i++) {
         sum += i;
    }
    System.out.println(sum);
}

इस कार्यक्रम को सही उत्तर मिलता है, लेकिन यह एक चरित्र टाइपोग्राफिक त्रुटि के कारण जितना होना चाहिए, उससे बहुत धीमा है। चर sumको एक के Longबजाय घोषित किया जाता है long, जिसका अर्थ है कि कार्यक्रम लगभग 2 ^ 31 अनावश्यक Longउदाहरणों का निर्माण करता है (लगभग हर बार जब long iयह जोड़ा जाता है Long sum)। मेरी मशीन पर रनटाइम को 43 सेकंड से 6.8 सेकंड Longतक longकम करने के लिए राशि की घोषणा को बदलना ।


2
यदि आप बलोच के कारणों को सूचीबद्ध करते हैं, तो यह उनके निष्कर्ष को उद्धृत करने के बजाय मदद करेगा!
वॉनथॉन्ड्रोइड

@Baqueta मैंने पोस्ट को संपादित किया है। कारण है प्रदर्शन।
m3th0dman

यह थोड़ा स्पष्ट है, धन्यवाद। मैं अब अपना जवाब पोस्ट करने में उचित महसूस करता हूं। :)
विघ्नहर्ता

आपको लगमैक्स आर्किटेक्चर दिलचस्प लग सकता है - "परिमाण के एक और क्रम को बढ़ाने के लिए थोड़ा अधिक चतुराई हुई। एलएमएक्स टीम को वहां पहुंचने में मदद मिली। एक था जावा संग्रह के कस्टम कार्यान्वयन लिखना। कचरा के साथ कैश-फ्रेंडली और सावधान रहना। इसका एक उदाहरण विशेष रूप से लिखित सरणी समर्थित मानचित्र कार्यान्वयन के साथ हैमैप कुंजियों के रूप में आदिम जावा लॉन्ग का उपयोग करना है । "

ऐसा लग रहा है कि जेआईटी को कुछ संभालना चाहिए
deFreitas

28

जब तक आप जेनरिक के साथ व्यवहार नहीं कर रहे हैं, तब तक मानक अभ्यास प्राथमिकताओं के साथ जाना है (सुनिश्चित करें कि आप ऑटोबॉक्सिंग और अनबॉक्सिंग के बारे में जानते हैं !)।

सम्मेलन का पालन करने के लिए कई अच्छे कारण हैं:

1. आप साधारण गलतियों से बचते हैं:

कुछ सूक्ष्म, गैर-सहज मामले हैं जो अक्सर शुरुआती को पकड़ते हैं। यहां तक ​​कि अनुभवी कोडर भी फिसल जाते हैं और कभी-कभी इन गलतियों को करते हैं (उम्मीद है कि जब वे कोड को डीबग करेंगे और त्रुटि का पता लगाएंगे!)

के a == bबजाय सबसे कमोन गलती का उपयोग कर रहा है a.equals(b)। लोगों का उपयोग a == bआदिम के साथ करने के लिए किया जाता है इसलिए यह आसानी से हो जाता है जब आप ऑब्जेक्ट रैपर का उपयोग कर रहे होते हैं।

Integer a = new Integer(2);
Integer b = new Integer(2);
if (a == b) { // Should be a.equals(b)
    // This never gets executed.
}
Integer c = Integer.valueOf(2);
Integer d = Integer.valueOf(2);
if (c == d) { // Should be a.equals(b), but happens to work with these particular values!
    // This will get executed
}
Integer e = 1000;
Integer f = 1000;
if (e == f) { // Should be a.equals(b)
    // Whether this gets executed depends on which compiler you use!
}

2. पढ़ें:

निम्नलिखित दो उदाहरणों पर विचार करें। अधिकांश लोग कहेंगे कि दूसरा अधिक पठनीय है।

Integer a = 2;
Integer b = 2;
if (!a.equals(b)) {
    // ...
}
int c = 2;
int d = 2;
if (c != d) {
    // ...
}

3. प्रदर्शन:

तथ्य यह है कि यह केवल प्राथमिकताओं का उपयोग करने की तुलना में प्राथमिकताओं के लिए ऑब्जेक्ट रैपर का उपयोग करने के लिए धीमा है। आप उन चीजों के लिए ऑब्जेक्ट इंस्टेंटेशन, मेथड कॉल आदि की लागत जोड़ रहे हैं जो आप सभी जगह उपयोग करते हैं ।

नुथ के "... समय के बारे में 97% का कहना है: समय से पहले अनुकूलन सभी बुराई की जड़ है" बोली वास्तव में यहां लागू नहीं होती है। वह उन अनुकूलन के बारे में बात कर रहा था जो कोड (या सिस्टम) को अधिक जटिल बनाते हैं - यदि आप बिंदु # 2 से सहमत हैं, तो यह एक अनुकूलन है जो कोड को कम जटिल बनाता है!

4. यह सम्मेलन है:

यदि आप अन्य जावा प्रोग्रामर के 99% अलग-अलग शैलीगत विकल्प चुनते हैं, तो 2 डाउनसाइड हैं:

  • आपको अन्य लोगों का कोड पढ़ने में कठिन लगेगा। 99% उदाहरण / ट्यूटोरियल / आदि बाहर आदिम का उपयोग करेंगे। जब भी आप एक को पढ़ते हैं, तो आपके पास यह सोचने का अतिरिक्त संज्ञानात्मक ओवरहेड होगा कि यह उस शैली में कैसे दिखाई देगा, जिसका आप उपयोग कर रहे हैं।
  • अन्य लोगों को आपका कोड पढ़ने में कठिन लगेगा। जब भी आप स्टैक ओवरफ्लो पर सवाल पूछते हैं, तो आपको जवाब / टिप्पणियों के माध्यम से यह पूछना होगा कि "आप आदिम का उपयोग क्यों नहीं कर रहे हैं?"। यदि आप मुझ पर विश्वास नहीं करते हैं, तो बस उन लड़ाइयों को देखें जिन पर लोगों के पास ब्रैकेट प्लेसमेंट जैसी चीजें हैं, जो उत्पन्न कोड को भी प्रभावित नहीं करता है!

आम तौर पर मैं कुछ प्रति-बिंदुओं की सूची बनाऊंगा, लेकिन मैं ईमानदारी से किसी भी अच्छे कारणों के बारे में नहीं सोच सकता, क्योंकि यहां अधिवेशन नहीं होगा!


2
लोगों के साथ वस्तुओं की तुलना करने के लिए चीनी मत करो ==। वस्तुओं की तुलना की जानी चाहिए equals()
ट्यूलेंस कोरडोवा

2
@ user61852 मैं सुझाव नहीं दे रहा था कि ऐसा करना है, लेकिन एक सामान्य गलती के रूप में! क्या मुझे यह स्पष्ट करना चाहिए?
विघ्नह्रदय

हां, आप यह उल्लेख नहीं करते हैं कि वस्तुओं की तुलना के साथ तुलना की जा सकती है equals()... आप उन्हें वर्कअराउंड देते हैं ताकि वस्तुओं की तुलना ==अपेक्षित परिणामों से की जा सके।
ट्यूलेंस कोरडोवा

अच्छी बात। उसे बदल दिया।

मैंने equals()दूसरे कोड स्निपेट में जोड़ा और अपना वोट बदल दिया।
ट्यूलेंस कोर्डोवा

12

आमतौर पर मैं आदिम लोगों के साथ जाता हूं। हालांकि, कक्षाओं का उपयोग करने की एक ख़ासियत Integerऔर उन चर को Booleanनिर्दिष्ट nullकरने की संभावना है । बेशक, इसका मतलब है कि आपको nullहर समय चेक करना होगा , लेकिन अभी भी NullPointerException पाने के लिए बेहतर है कि कुछ intया booleanवैरिएबल का उपयोग करने की वजह से लॉजिक एरर्स हो, जिन्हें सही तरीके से इनिशियलाइज़ नहीं किया गया है।

बेशक, जावा 8 के बाद से आप (और शायद चाहिए) एक कदम आगे बढ़ सकते हैं और इसके बजाय उदाहरण के लिए Integerआप उन Optional<Integer>चर के लिए उपयोग कर सकते हैं जिनका मूल्य हो सकता है या नहीं हो सकता है।

इसके अतिरिक्त, यह nullउन चर को " अज्ञात " या " वाइल्डकार्ड " मान निर्दिष्ट करने के लिए उपयोग करने की संभावना का परिचय देता है । यह कुछ स्थितियों में आसान हो सकता है, उदाहरण के लिए, टेरनेरी लॉजिक में । या आप जांचना चाहते हैं कि क्या एक निश्चित वस्तु कुछ टेम्पलेट से मेल खाती है; इस मामले में आप nullटेम्पलेट में उन चरों के लिए उपयोग कर सकते हैं जिनका ऑब्जेक्ट में कोई मूल्य हो सकता है।


2
(मेरा डाउनवोट नहीं था, लेकिन ...) जावा पहले से ही अनइंस्टॉल किए गए वेरिएबल्स का पता लगाता है, और आपको एक चर झुकाव को पढ़ने नहीं देगा, जिससे इसके उपयोग के लिए अग्रणी प्रत्येक कोड पथ निश्चित रूप से एक मान असाइन किया गया है। तो आप nullएक डिफ़ॉल्ट के रूप में असाइन करने की क्षमता से ज्यादा हासिल नहीं करते हैं । इसके विपरीत: आप बेहतर होगा कि वेरिएबल को "इनिशियलाइज़" न करें। कोई भी डिफ़ॉल्ट मान सेट करना, यहां nullतक कि कंपाइलर को बंद कर देता है ... लेकिन यह सभी कोड रास्तों के साथ उपयोगी असाइनमेंट की कमी का पता लगाने से भी बचाता है । इस प्रकार, एक त्रुटि संकलक को पकड़ा जा सकता है, रनटाइम के माध्यम से फिसल जाता है।
cHao

@ cHao लेकिन अगर चर को आरंभ करने के लिए कोई समझदार डिफ़ॉल्ट मान नहीं है तो क्या होगा ? आप इसे सेट कर सकते हैं 0.0, या -1, या Integer.MAX_VALUE, या Falseअंत में, लेकिन अंत में आपको नहीं पता कि यह डिफ़ॉल्ट मान है, या वास्तविक मूल्य जो उस चर को सौंपा गया है। ऐसे मामलों में जहां यह महत्वपूर्ण है, nullवहां मूल्य होना स्पष्ट हो सकता है।
टोबियास_

यह स्पष्ट नहीं है, संकलक को यह बताना आसान है कि आप अस्पष्ट तर्क के बारे में चेतावनी न दें जब तक कि बग पहले से ही प्रचारित न हो। : P ऐसे मामलों में जहां कोई समझदार डिफ़ॉल्ट नहीं है, चर को प्रारंभ न करें। इसे लगाने के लिए एक बार आपके पास एक समझदार मूल्य होने के बाद ही इसे सेट करें। यदि आपका मान सही ढंग से सेट नहीं किया जा सकता है, तो जावा आपको संकलन समय पर रोक देता है।
cHao

मैं @cHao मतलब, ऐसे मामले हैं जहां हो सकता है नहीं कर सकते हैं चर इनिशिएलाइज़ और आप के लिए है कार्यावधि में इसके साथ सौदा। ऐसे मामलों में, एक "डिफ़ॉल्ट" जैसे "नल", जिसे स्पष्ट रूप से डिफ़ॉल्ट होने के रूप में पहचाना जा सकता है, या "अनइंस्टॉल किया गया" हो सकता है, किसी भी संकलन-समय के आरंभीकरण से बेहतर हो सकता है जो एक वैध मूल्य भी हो सकता है।
टोबियास_

क्या आपके मन में ऐसा कोई मामला है? मैं जिन मामलों के बारे में सोच सकता हूं वे इंटरफ़ेस सीमाओं (जैसे: पैरामीटर या रिटर्न प्रकार) के रूप में हैं ... लेकिन वहां भी, वे लिपटे हुए से बहुत बेहतर होंगे। (नग्न nullएस समस्याओं की एक पूरी मेजबानी के साथ आते हैं, जिसमें शून्य व्यामोह भी शामिल है।) एक फ़ंक्शन के भीतर, एक चर जो वास्तव में उपयोग के बिंदु पर एकतरफा हो सकता है, आमतौर पर अनियोजित मामलों को इंगित करता है। (निश्चित असाइनमेंट विश्लेषण सरल है, इसलिए झूठी सकारात्मकता संभव है। लेकिन आप अक्सर तर्क को सरल बनाने के द्वारा उन्हें हल कर सकते हैं, इसलिए।)
cHao

2

आम आदमी के शब्दों में:

जब आप चीजों को संग्रह में जोड़ने की आवश्यकता होती है तो आप रैपर का उपयोग करते हैं।

संग्रह आदिम नहीं हो सकते।


0

Java में m3th0dman के रूप में ऑटोबॉक्सिंग की सुविधा है। सबसे कम संभव स्तर के बारे में सोचें और आप देखेंगे कि ऑटोबॉक्सिंग (इन या आउट) एक आदिम मूल्य कुछ कार्यों में खर्च किए गए घड़ी चक्र होगा, जिनकी आपको जरूरत नहीं है यदि आप अपने एप्लिकेशन के आसपास मूल डेटा प्रकारों के साथ काम कर रहे हैं।

एक सामान्य नियम के रूप में, आपको जब भी संभव हो देशी डेटा प्रकारों का उपयोग करने का प्रयास करना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.