2010-02-05 6 views
25
package myintergertest; 

/** 
* 
* @author Engineering 
*/ 
public class Main { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     //this one does not increment 
     Integer n = new Integer(0); 
     System.out.println("n=" + n); 
     Increment(n); 
     System.out.println("n=" + n); 
     Increment(n); 
     System.out.println("n=" + n); 
     Increment(n); 
     System.out.println("n=" + n); 
     Increment(n); 

     //this one will increment 
     MyIntegerObj myInt = new MyIntegerObj(1); 
     Increment(myInt); 
     System.out.println("myint = " + myInt.get()); 
     Increment(myInt); 
     System.out.println("myint = " + myInt.get()); 
     Increment(myInt); 
     System.out.println("myint = " + myInt.get()); 

    } 

    public static void Increment(Integer n) { 
     //NO. this doesn't work because a new reference is being assigned 
     //and references are passed by value in java 
     n++; 
    } 

    public static void Increment(MyIntegerObj n) { 
     //this works because we're still operating on the same object 
     //no new reference was assigned to n here. 
     n.plusplus(); //I didn't know how to implement a ++ operator... 
    } 
} 

उन सभी के लिए परिणाम n = 0 है। इंटीजर एन एक ऑब्जेक्ट है और इसलिए संदर्भ द्वारा पारित किया गया है, तो कॉलर विधि (मुख्य) में वृद्धि क्यों नहीं दिखाई देती है? मुझे आउटपुट होने की उम्मीद है n = 0 n = 1 n = 2 आदि ...किसी अन्य विधि से जावा में एक वर्ग इंटीजर संदर्भ मान कैसे बढ़ाएं

अद्यतन: नोटिस मैंने उपरोक्त कोड उदाहरण अपडेट किया है। अगर मैं सही ढंग से समझ रहा हूं, तो जॉन स्कीट ने इस सवाल का जवाब दिया कि मेरा इंटेंट क्यों बढ़ेगा और क्यों नहीं। ऐसा इसलिए है क्योंकि एन को बढ़ती विधि में एक नया संदर्भ दिया गया है। लेकिन मेरे सदस्य को एक नया फ़ंक्शन असाइन नहीं किया गया है क्योंकि यह सदस्य फ़ंक्शन को कॉल कर रहा है।

क्या ऐसा लगता है जैसे मैं सही ढंग से समझता हूं?

उत्तर

36

नहीं, ऑब्जेक्ट संदर्भ द्वारा पारित नहीं किए जाते हैं। संदर्भ मूल्य से पारित होते हैं - एक बड़ा अंतर है। Integer एक अपरिवर्तनीय प्रकार है, इसलिए आप विधि के भीतर मान नहीं बदल सकते हैं।

आपका n++; बयान को प्रभावी ढंग से

n = Integer.valueOf(n.intValue() + 1); 

तो, कि Increment में चर n के लिए एक अलग मूल्य प्रदान करती है - लेकिन जावा के रूप में केवल पारित-दर-मूल्य, कि मूल्य को प्रभावित नहीं करता है कॉलिंग विधि में n का।

संपादित करें: अपने अपडेट का जवाब देने के लिए: यह सही है। संभवतः आपका "MyIntegerObj" प्रकार mutable है, और जब आप plusplus() पर कॉल करते हैं तो इसकी आंतरिक स्थिति बदलती है। ओह, और एक ऑपरेटर को कार्यान्वित करने के लिए चारों ओर देखकर परेशान न करें - जावा उपयोगकर्ता द्वारा परिभाषित ऑपरेटरों का समर्थन नहीं करता है।

+0

क्या आप कहने का मतलब था '** ऑब्जेक्ट्स ** मूल्य से गुजर चुके हैं - ...'? – FrustratedWithFormsDesigner

+8

नहीं, उसने नहीं किया।Primitives और संदर्भ मूल्य से पारित कर रहे हैं। वस्तुएं बिल्कुल पारित नहीं होती हैं; वे ढेर पर रहते हैं। – danben

+0

मुझे लगता है कि मैं समझता हूं, मेरे अपडेट देखता हूं और मुझे बताता हूं। धन्यवाद!!! – cchampion

6

आप सी ++ के संदर्भ या सी # आउट पैरामीटर के समान कुछ ढूंढ रहे हैं। जावा (और कई अन्य भाषाओं) इसका समर्थन नहीं करता है।

व्यवहार के इस प्रकार के आम तौर पर करने के लिए शून्य से विधि बदलकर हासिल की है (इस मामले में) int: पद्धति पहले से ही कुछ लौटा रहा है public static int increment(int n) { return ++n; }

हैं तो आप एक नया वर्ग दो क्षेत्रों बना सकते हैं जिनमें (कर सकते हैं यहां तक ​​कि सार्वजनिक भी हो): मूल वापसी मूल्य और एन का नया मूल्य।

वैकल्पिक रूप से, आप एक सामान्य सेल क्लास के अंदर पूर्णांक को भी लपेट सकते हैं।

public class Cell<T> { 
    public Cell(T t) { value = t; } 
    public void set(T t) { value = t; } 
    public T get() { return value; } 
} 

फिर आप सभी स्थितियों में उपयोग कर सकते हैं एक तरीका है करने के लिए अपने इच्छित स्थान को बदलने के लिए एक आदिम:

public static void increment(Cell<Integer> n) { 
    n.set(n.get()++); 
} 

Cell<Integer> n = new Cell<Integer>(0); 
increment(n); 
increment(n); 
increment(n); 
System.out.println(n.get()); // Output: 3 
22

आप एक AtomicIntegerjava.util.concurrent.atomic से इस्तेमाल कर सकते हैं तो आप केवल यह सेल वर्ग एक बार लिखने की ज़रूरत । इसमें 'incrementAndGet' विधि है जो आपके शोकेस के लिए उपयुक्त है।

+0

क्या? हाँ, मेरा मतलब है कि यह काम करता है, लेकिन यह वास्तव में एक अच्छा विचार नहीं है। यह आपके प्रोसेसर के बफर सिंक्रनाइज़ करने जैसी चीजें करेगा, क्योंकि यह अन्यथा परमाणु संचालन नहीं है। असल में, आपको डेटा प्रकार के परमाणु संस्करण का उपयोग नहीं करना चाहिए जबतक कि आपको उस परमाणुता की आवश्यकता न हो ... – Jasper

+0

@ जैस्पर, मैं इसके साथ बहस नहीं कर सकता। यह मेरे टूलबॉक्स में बस एक और टूल है। मैं काम पर निर्भर करता हूं। और जब तक कि प्रोफाइलर उस विशेष बिंदु पर कोई समस्या नहीं बताता है, यह एक विकल्प बना रहता है। – DerMike

1

Integer एक value object है जिसका अर्थ है कि मूल्य बदल नहीं सकता है।

ध्यान दें कि n++n = n + 1 के बराबर है। आप केवल स्थानीय चर n द्वारा संदर्भित मान को बदल रहे हैं, n के मूल्य का नहीं।

2

आप नहीं कर सकते। जावा कड़ाई से पास-दर-मूल्य है।

देखें http://javadude.com/articles/passbyvalue.htm

आपके विकल्प एक वस्तु (या सरणी) में पूर्णांक रैप करने के लिए कर रहे हैं, में और अद्यतन पारित है कि कोई मान, या पूर्णांक एक वर्ग/उदाहरण चर बनाते हैं।

कौन सा बेहतर है की स्थिति पर निर्भर करता है।

3

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

हालांकि, अगर आप समारोह शरीर के अंदर प्रति पुन: असाइन, यह अपने कार्यक्रम के बाकी पर कोई प्रभाव नहीं के रूप में है कि प्रति दायरे से जब समारोह रास्ते बाहर जाना होगा।

लेकिन विचार है कि तुम सच में नहीं है पारित-दर-संदर्भ है कि आप क्या करना चाहते हैं की जरूरत है। उदाहरण के लिए, आपको Integer बढ़ाने के लिए किसी विधि की आवश्यकता नहीं है - आप इसे अपने कोड के उस बिंदु पर बढ़ा सकते हैं जहां इसे बढ़ाना आवश्यक है।

अधिक जटिल प्रकार के लिए, एक वस्तु पर कुछ संपत्ति सेट करने जैसी वस्तु आप के साथ काम कर रहे हैं संभावना परिवर्तनशील है, उस स्थिति में संदर्भ की एक प्रति ठीक काम करती है, क्योंकि स्वत: dereference आपको उस मूल ऑब्जेक्ट पर ले जाएगा जिसके सेटर आप कॉल कर रहे हैं।

3

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

एक:: वेतन वृद्धि समारोह अद्यतन मूल्य के साथ एक नया पूर्णांक लौटने है

वैसे भी, आप जाहिरा तौर पर ऐसा करने के लिए कोशिश कर रहे हैं पूरा करने के लिए दो तरीके हैं। जैसा:

Integer n=Integer.valueOf(0); 
n=increment(n); // now n==1 
n=increment(n); // now n==2 

आदि

दो:

public Integer increment(Integer n) 
    { 
     Integer nPlus=Integer.valueOf(n.intValue()+1); 
    } 

तो इसके साथ फोन अपने ही वर्ग है कि पूर्णांक जैसा दिखता बनाएं लेकिन वह परिवर्तनशील है। पसंद:

class MutableInteger 
{ 
    int value; 
    public MutableInteger(int n) 
    { 
    value=n; 
    } 
    public void increment() 
    { 
    ++value; 
    } 
    ... whatever other functions you need ... 
} 

बेशक इसका बड़ा पकड़ यह है कि आपको इंटीजर क्लास को फिर से आविष्कार करना होगा। यह थ्रेड-सुरक्षित इस java.util.concurrent वर्ग का उपयोग कर आप क्या कर सकते हैं http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html

:

2

रूप DerMike उल्लेख इस प्रकार आप इस लक्ष्य को हासिल कर सकते हैं:

public void doStuff() { 
    AtomicInteger i = new AtomicInteger(0); 
    increment(i); 
    System.out.println(i); 
} 

    public void increment(AtomicInteger i) { 
    i.set(i.get() + 1); 
} 
संबंधित मुद्दे