कैसे जावा में आदिम के लिए संदर्भ द्वारा पास के बराबर करने के लिए


116

यह जावा कोड:

public class XYZ {   
    public static void main(){  
        int toyNumber = 5;   
        XYZ temp = new XYZ();  
        temp.play(toyNumber);  
        System.out.println("Toy number in main " + toyNumber);  
    }

    void play(int toyNumber){  
        System.out.println("Toy number in play " + toyNumber);   
        toyNumber++;  
        System.out.println("Toy number in play after increement " + toyNumber);   
    }   
}  

इसका उत्पादन करेगा:

 
खेल में खिलौना नंबर 5  
क्रीड़ा में खिलौना नंबर 6 के बाद  
मुख्य 5 में खिलौना नंबर  

C ++ में मैं toyNumberछायांकन से बचने के लिए संदर्भ के रूप में चर को पास कर सकता हूं अर्थात नीचे के रूप में एक ही चर की एक प्रति बना सकता हूं :

void main(){  
    int toyNumber = 5;  
    play(toyNumber);  
    cout << "Toy number in main " << toyNumber << endl;  
}

void play(int &toyNumber){  
    cout << "Toy number in play " << toyNumber << endl;   
    toyNumber++;  
    cout << "Toy number in play after increement " << toyNumber << endl;   
} 

और C ++ आउटपुट यह होगा:

खेल में खिलौना नंबर 5  
क्रीड़ा में खिलौना नंबर 6 के बाद  
मुख्य 6 में खिलौना नंबर  

मेरा प्रश्न है - जावा में समान कोड C ++ कोड के समान आउटपुट प्राप्त करने के लिए है, यह देखते हुए कि जावा संदर्भ के लिए पास होने के बजाय मूल्य से पास है ?


22
यह मेरे लिए एक डुप्लिकेट की तरह प्रतीत नहीं होता है - माना जाता है कि डुप्लिकेट प्रश्न इस बात से संबंधित है कि जावा कैसे काम करता है और शर्तों का क्या मतलब है, जो कि शिक्षा है, जबकि यह प्रश्न विशेष रूप से पूछता है कि पास-बाय-रेफरेंस व्यवहार से मिलता-जुलता कुछ कैसे प्राप्त करें, कुछ सी / C ++ / D / Ada प्रोग्रामर व्यावहारिक कार्य करने के लिए सोच रहे होंगे, यह ध्यान नहीं रखते कि जावा सभी पास-पास क्यों है।
डेरेनव

1
@DarenW मैं पूरी तरह से सहमत हूँ - फिर से खोलने के लिए मतदान किया है। ओह, और आपके पास एक ही करने के लिए पर्याप्त प्रतिष्ठा है :-)
डंकन जोन्स

आदिम के चारों ओर चर्चा बल्कि भ्रामक है, क्योंकि प्रश्न संदर्भ मूल्यों पर समान रूप से लागू होता है।
शमोसल

"C ++ में मैं टॉयअनम्बर चर को छायांकन से बचने के लिए संदर्भ के रूप में पास कर सकता हूं" - यह शैडोइंग नहीं है क्योंकि विधि toyNumberमें घोषित चर mainविधि में गुंजाइश नहीं है play। C ++ और Java में शैडो करना केवल तब होता है जब स्कोप का घोंसला होता है। En.wikipedia.org/wiki/Variable_shadowing देखें ।
स्टीफन सी

जवाबों:


171

आपके पास कई विकल्प हैं। जो सबसे अधिक समझ में आता है वह वास्तव में इस बात पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं।

विकल्प 1: ToyNumber को एक कक्षा में एक सार्वजनिक सदस्य चर बनाते हैं

class MyToy {
  public int toyNumber;
}

फिर अपनी विधि के लिए एक MyToy का संदर्भ दें।

void play(MyToy toy){  
    System.out.println("Toy number in play " + toy.toyNumber);   
    toy.toyNumber++;  
    System.out.println("Toy number in play after increement " + toy.toyNumber);   
}

विकल्प 2: संदर्भ द्वारा पास के बजाय मान लौटाएं

int play(int toyNumber){  
    System.out.println("Toy number in play " + toyNumber);   
    toyNumber++;  
    System.out.println("Toy number in play after increement " + toyNumber);   
    return toyNumber
}

इस विकल्प को मुख्य रूप से कॉलसाइट में एक छोटे से बदलाव की आवश्यकता होगी ताकि यह पढ़े toyNumber = temp.play(toyNumber);,।

विकल्प 3: इसे एक वर्ग या स्थिर चर बनाते हैं

यदि दो कार्य एक ही वर्ग या वर्ग उदाहरण पर विधियाँ हैं, तो आप टॉयअनम्बर को एक वर्ग सदस्य चर में बदल सकते हैं।

विकल्प 4: इंट का एकल तत्व सरणी बनाएं और पास करें

यह एक हैक माना जाता है, लेकिन कभी-कभी इनलाइन क्लास इनवोकेशन से मूल्यों को वापस करने के लिए नियोजित किया जाता है।

void play(int [] toyNumber){  
    System.out.println("Toy number in play " + toyNumber[0]);   
    toyNumber[0]++;  
    System.out.println("Toy number in play after increement " + toyNumber[0]);   
}

2
स्पष्ट विवरण और विशेष रूप से वांछित प्रभाव के लिए कोड के कई विकल्प प्रदान करने के लिए अच्छा है। सीधे मैं अभी काम कर रहा हूँ कुछ के लिए उपयोगी! यह पागल है कि यह सवाल बंद कर दिया गया था।
डैरेनडब्ल्यू

1
यद्यपि आपकी पसंद 1 वही करती है जो आप व्यक्त करने की कोशिश कर रहे हैं, मुझे वास्तव में वापस जाना था और इसकी दोहरी जांच करनी थी। सवाल पूछता है कि क्या आप संदर्भ से गुजर सकते हैं; तो वास्तव में आपको उसी स्कोप में प्रिंटलैन्स करना चाहिए था जो कि फंक्शन में पास किया गया खिलौना मौजूद है। जिस तरह से आपके पास है, प्रिंटलैन्स को उसी स्कोप में संचालित किया जाता है, जो इंक्रीमेंट को साबित नहीं करता है। वेतन वृद्धि के बाद प्रिंट की गई एक स्थानीय प्रति का एक अलग मूल्य होगा, हालांकि इसका मतलब यह नहीं है कि पारित संदर्भ होगा। फिर भी, आपका उदाहरण काम करता है, लेकिन बात साबित नहीं होती है।
शून्य 298

नहीं, मुझे लगता है कि यह सही तरीका है। ऊपर दिए गए मेरे जवाब में प्रत्येक फ़ंक्शन "प्ले ()" का उद्देश्य मूल "प्ले ()" फ़ंक्शन के लिए ड्रॉप-इन प्रतिस्थापन के रूप में किया गया है, जो वेतन वृद्धि से पहले और बाद में मूल्य भी मुद्रित करता है। मूल प्रश्न में मुख्य रूप से प्रिंटलाइन () है जो संदर्भ से गुजरती है।
लसलोव सिप 9'13

च्वाइस 2 को और स्पष्टीकरण की आवश्यकता है: मुख्य रूप से कॉल साइट को toyNumber = temp.play(toyNumber);इसे वांछित रूप से काम करने के लिए बदलना चाहिए ।
टूलमेकरसैट

1
यह बहुत ही बदसूरत है और इसे हैक करने का मन करता है ... क्यों इतना बुनियादी कुछ भाषा का हिस्सा नहीं है?
shinzou

30

जावा को केवल संदर्भ के आधार पर कॉल नहीं किया जाता है

लेकिन वस्तु प्रकार के सभी चर वास्तव में संकेत हैं।

इसलिए यदि आप एक Mutable ऑब्जेक्ट का उपयोग करते हैं, तो आप अपने इच्छित व्यवहार को देखेंगे

public class XYZ {

    public static void main(String[] arg) {
        StringBuilder toyNumber = new StringBuilder("5");
        play(toyNumber);
        System.out.println("Toy number in main " + toyNumber);
    }

    private static void play(StringBuilder toyNumber) {
        System.out.println("Toy number in play " + toyNumber);
        toyNumber.append(" + 1");
        System.out.println("Toy number in play after increement " + toyNumber);
    }
}

इस कोड का आउटपुट:

run:
Toy number in play 5
Toy number in play after increement 5 + 1
Toy number in main 5 + 1
BUILD SUCCESSFUL (total time: 0 seconds)

आप इस व्यवहार को मानक पुस्तकालयों में भी देख सकते हैं। उदाहरण के लिए Collections.sort (); Collections.shuffle (); ये विधियाँ एक नई सूची नहीं लौटाती हैं, लेकिन यह तर्क वस्तु को संशोधित करती हैं।

    List<Integer> mutableList = new ArrayList<Integer>();

    mutableList.add(1);
    mutableList.add(2);
    mutableList.add(3);
    mutableList.add(4);
    mutableList.add(5);

    System.out.println(mutableList);

    Collections.shuffle(mutableList);

    System.out.println(mutableList);

    Collections.sort(mutableList);

    System.out.println(mutableList);

इस कोड का आउटपुट:

run:
[1, 2, 3, 4, 5]
[3, 4, 1, 5, 2]
[1, 2, 3, 4, 5]
BUILD SUCCESSFUL (total time: 0 seconds)

2
यह सवाल का जवाब नहीं है। यदि यह एक पूर्णांक सरणी बनाने का सुझाव देता है, जिसमें एक तत्व होता है, और फिर उस तत्व को विधि के भीतर संशोधित करने का सुझाव देता है play; उदा mutableList[0] = mutableList[0] + 1;। जैसा कि अर्नेस्ट फ्राइडमैन-हिल सुझाते हैं।
टूलमेकरसैट जूल 23'14

गैर-प्राथमिकताओं के साथ। ऑब्जेक्ट का मान एक संदर्भ नहीं है। शायद आप कहना चाहते थे: "पैरामीटर मान" "एक संदर्भ" है। संदर्भ मूल्य द्वारा पारित किए जाते हैं।
vlakov

मैं ऐसा ही कुछ करने की कोशिश कर रहा हूं, लेकिन आपके कोड में, विधि private static void play(StringBuilder toyNumber)- यदि आप इसका उदाहरण सार्वजनिक स्थैतिक int जो पूर्णांक लौटा रहे हैं , तो आप इसे कैसे कॉल करेंगे? क्योंकि मेरे पास एक तरीका है जो एक नंबर देता है लेकिन अगर मैं इसे कहीं नहीं बुलाता हूं, तो यह उपयोग में नहीं है।
फ्रैंक 17

18

एक बनाओ

class PassMeByRef { public int theValue; }

फिर इसके एक उदाहरण के संदर्भ में पास करें। ध्यान दें कि एक विधि जो अपने तर्कों के माध्यम से राज्य को उत्परिवर्तित करती है, विशेष रूप से समानांतर कोड में सबसे बेहतर है।


3
मेरे द्वारा नीचा दिखाया गया। यह कई सारे स्तरों पर गलत है। जावा हमेशा मूल्य से गुजरता है। कोई अपवाद नहीं।
duffymo

14
@duffymo - निश्चित रूप से आप कृपया नीचे बता सकते हैं - लेकिन क्या आपने विचार किया है कि ओपी ने क्या पूछा है? वह संदर्भ द्वारा पास और इंट करना चाहता है - और अगर मैं ऊपर के एक उदाहरण के संदर्भ में मूल्य से गुजरता हूं तो यह पूरा होता है।
इंगो

7
@duffymo: हुह? आपसे गलती हुई है, वरना सवाल गलत समझ लेते हैं। यह है क्या ओ पी अनुरोध करने का जावा में पारंपरिक तरीकों में से एक।
टूलमेकरसैट

5
@duffymo: आपकी टिप्पणी इतने सारे स्तरों पर गलत है। एसओ उपयोगी उत्तर और टिप्पणियां प्रदान करने के बारे में है, और आप सिर्फ एक सही उत्तर को केवल इसलिए नीचे कर देते हैं क्योंकि (मुझे लगता है) यह आपकी प्रोग्रामिंग शैली और दर्शन के अनुरूप नहीं है। क्या आप कम से कम एक बेहतर स्पष्टीकरण या मूल प्रश्न का बेहतर उत्तर दे सकते हैं?
पियरसेबल

2
@duffymo है कि वास्तव में क्या मैंने कहा है: मूल्य से एक रेफ पास। आपको क्या लगता है कि Ref के द्वारा पास होने वाली भाषाओं को कैसे पूरा किया जाता है?
इंगो

11

आप जावा में संदर्भ द्वारा प्राइमेटिव पास नहीं कर सकते। ऑब्जेक्ट प्रकार के सभी चर वास्तव में संकेत हैं, लेकिन हम उन्हें "संदर्भ" कहते हैं, और वे हमेशा मूल्य से भी पारित होते हैं।

ऐसी स्थिति में जब आपको वास्तव में संदर्भ द्वारा एक आदिम पारित करने की आवश्यकता होती है, तो लोग क्या करेंगे कभी-कभी पैरामीटर को आदिम प्रकार के एक सरणी के रूप में घोषित किया जाता है, और फिर तर्क के रूप में एकल-तत्व सरणी पास करें। इसलिए आप एक संदर्भ int [1] पास करते हैं, और विधि में, आप ऐरे की सामग्री को बदल सकते हैं।


1
नहीं - सभी आवरण वर्ग अपरिवर्तनीय हैं - वे एक निश्चित मूल्य का प्रतिनिधित्व करते हैं जिसे ऑब्जेक्ट के बनने के बाद नहीं बदला जा सकता है।
अर्नेस्ट फ्राइडमैन-हिल

1
"आप जावा में संदर्भ द्वारा प्राइमिटिव को पास नहीं कर सकते हैं": ओपी को यह समझ में आता है, क्योंकि वे जावा के साथ C ++ (जहाँ आप कर सकते हैं) के विपरीत हैं।
रायडवल

यह ध्यान दिया जाना चाहिए कि अर्नेस्ट द्वारा JDK के बिल्ड-इन इंटेगर, डबल, लॉन्ग, आदि पर "सभी रैपर क्लासेस अपरिवर्तनीय हैं" आप अपने कस्टम रैपर क्लास के साथ इस प्रतिबंध को दरकिनार कर सकते हैं, जैसे अहंकार का जवाब क्या था।
user3207158

10

एक त्वरित समाधान के लिए, आप AtomicInteger या किसी भी परमाणु चर का उपयोग कर सकते हैं जो आपको इनबिल्ट विधियों का उपयोग करके विधि के अंदर मूल्य को बदलने देगा। यहाँ नमूना कोड है:

import java.util.concurrent.atomic.AtomicInteger;


public class PrimitivePassByReferenceSample {

    /**
     * @param args
     */
    public static void main(String[] args) {

        AtomicInteger myNumber = new AtomicInteger(0);
        System.out.println("MyNumber before method Call:" + myNumber.get());
        PrimitivePassByReferenceSample temp = new PrimitivePassByReferenceSample() ;
        temp.changeMyNumber(myNumber);
        System.out.println("MyNumber After method Call:" + myNumber.get());


    }

     void changeMyNumber(AtomicInteger myNumber) {
        myNumber.getAndSet(100);

    }

}

आउटपुट:

MyNumber before method Call:0

MyNumber After method Call:100

मैं इस समाधान का उपयोग और इसे पसंद करता हूं क्योंकि यह अच्छी यौगिक क्रियाएं प्रदान करता है और समवर्ती कार्यक्रमों में एकीकृत करना आसान है जो पहले से ही या भविष्य में इन परमाणु वर्गों का उपयोग करना चाहते हैं।
RAnders00

2
public static void main(String[] args) {
    int[] toyNumber = new int[] {5};
    NewClass temp = new NewClass();
    temp.play(toyNumber);
    System.out.println("Toy number in main " + toyNumber[0]);
}

void play(int[] toyNumber){
    System.out.println("Toy number in play " + toyNumber[0]);
    toyNumber[0]++;
    System.out.println("Toy number in play after increement " + toyNumber[0]);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.