क्या इंटेगर इम्युटेबल है


101

मुझे पता है कि यह शायद बहुत ही मूर्खतापूर्ण है, लेकिन बहुत सी जगहों का दावा है कि जावा में इंटेगर वर्ग अपरिवर्तनीय है, फिर भी निम्नलिखित कोड है:

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

(अपेक्षित) परिणाम देने में किसी भी परेशानी के बिना परिणाम 6. इतना प्रभावी रूप से एक मूल्य बदल गया है। इसका मतलब यह नहीं है कि इंटेगर म्यूट है? द्वितीयक प्रश्न और थोड़ा आक्रामक: "अपरिवर्तनीय वर्गों को कॉपी कंस्ट्रक्टर की आवश्यकता नहीं है"। किसी को भी समझाने की परवाह क्यों?


12
वर्ग अपरिवर्तनीय है, लेकिन
ऑटोबॉक्सिंग से

धन्यवाद, बॉक्सिंग वह कीवर्ड था जिसकी मुझे Google को आवश्यकता थी :)
K.Steff

7
आप एक अंतिम या निरंतर मूल्य के साथ अपरिवर्तनीय भ्रमित कर रहे हैं।
कोड उत्साही

जवाबों:


95

अपरिवर्तनीय का मतलब यह नहीं है कि aकभी भी दूसरे मूल्य के बराबर नहीं हो सकता है। उदाहरण के लिए, Stringअपरिवर्तनीय भी है, लेकिन मैं अभी भी ऐसा कर सकता हूं:

String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"

strनहीं बदला गया था, बल्कि strअब पूरी तरह से एक नई तात्कालिक वस्तु है, जैसा कि आपका Integerहै। इसलिए मूल्य का aपरिवर्तन नहीं हुआ, लेकिन इसे पूरी तरह से एक नई वस्तु के साथ बदल दिया गया था new Integer(6)


14
"यह इसलिए है क्योंकि str अब एक पूरी तरह से नई तात्कालिक वस्तु है"। या, बल्कि, str (एक varibale) अंक एक नई वस्तु है। ऑब्जेक्ट अपने आप में परिवर्तनशील नहीं है, लेकिन चूंकि चर अंतिम नहीं है, इसलिए यह एक अलग ऑब्जेक्ट को इंगित कर सकता है।
संध्या

हां, यह एक अलग वस्तु की ओर इशारा करता है जिसे +=ऑपरेशन के परिणामस्वरूप तुरंत हटा दिया गया था ।
ट्रैविस वेब

11
सच पूछिये तो, यह की जरूरत नहीं एक हो नई वस्तु। बॉक्सिंग का उपयोग करता है Integer.valueOf(int)और उस विधि से Integerवस्तुओं का कैश बना रहता है। इसलिए +=एक Integerचर पर परिणाम एक ऐसी वस्तु हो सकती है जो पहले से मौजूद थी (या यह भी उसी वस्तु हो सकती है ... के मामले में a += 0)।
स्टीफन सी

1
स्ट्रिंग के लिए JavaDoc को स्पष्ट रूप से अपरिवर्तनीय क्यों कहा जाता है, लेकिन पूर्णांक के लिए JavaDoc नहीं करता है? यही कारण है कि मैं यह प्रश्न पढ़ रहा हूं ...
cellepo

51

aकुछ इंटेगर (3) के लिए एक "संदर्भ" है, आपका आशुलिपि a+=bवास्तव में इसका मतलब है:

a = new Integer(3 + 3)

तो नहीं, इंटेगर म्यूट नहीं हैं, लेकिन चर जो उन्हें इंगित करते हैं वे हैं *।

* अपरिवर्तनीय चर होना संभव है, इन्हें कीवर्ड द्वारा निरूपित किया जाता है final, जिसका अर्थ है कि संदर्भ नहीं बदल सकता है।

final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.

19

आप यह निर्धारित कर सकते हैं कि ऑब्जेक्ट का उपयोग करके बदल गया है System.identityHashCode()(एक बेहतर तरीका सादे का उपयोग करना है, ==हालांकि यह स्पष्ट नहीं है कि मूल्य के बजाय संदर्भ बदल गया है)

Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));

प्रिंट

before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda

आप देख सकते हैं कि वस्तु का अंतर्निहित "आईडी" aबदल गया है।


1
System.identityHashCode () एक बहुत अच्छा टिप है। इसके लिए धन्यवाद।
विज्ञापन इनफिनिटम

11

पूछे जाने वाले प्रारंभिक प्रश्न के लिए,

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

पूर्णांक अपरिवर्तनीय है, इसलिए जो ऊपर हुआ है वह 'a' मान के एक नए संदर्भ में बदल गया है। 6. प्रारंभिक मान 3 को मेमोरी में कोई संदर्भ नहीं दिया गया है (इसे बदला नहीं गया है), इसलिए इसे कचरा एकत्र किया जा सकता है।

यदि यह एक स्ट्रिंग के लिए होता है, तो यह इंटर्जेन्स की तुलना में अधिक समय तक पूल (पर्मगेन स्थान) में रहेगा क्योंकि यह संदर्भों की अपेक्षा रखता है।


8

हाँ इंटेगर अपरिवर्तनीय है।

A एक संदर्भ है जो किसी वस्तु की ओर इशारा करता है। जब आप एक + = 3 चलाते हैं, तो एक अलग मान के साथ एक नया इंटेगर ऑब्जेक्ट को संदर्भित करने के लिए A को पुन: असाइन करता है।

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

वस्तुओं और संदर्भ के बीच अंतर के बारे में पढ़ें यहाँ


एक आम आदमी की भाषा में बस और आसानी से कहा गया, अन्य सभी जटिल स्पष्टीकरणों के साथ :)
रोशन फर्नांडो

5

अपरिवर्तनीय का मतलब यह नहीं है कि आप एक चर के लिए मूल्य नहीं बदल सकते। इसका मतलब सिर्फ इतना है कि कोई भी नया असाइनमेंट एक नई ऑब्जेक्ट बनाता है (इसे एक नया मेमोरी लोकेशन असाइन करता है) और फिर वैल्यू को असाइन किया जाता है।

अपने लिए इसे समझने के लिए, लूप में पूर्णांक असाइनमेंट करें (लूप के बाहर घोषित पूर्णांक के साथ) और स्मृति में जीवित वस्तुओं को देखें।

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


2

"अपरिवर्तनीय वर्गों को कॉपी बिल्डरों की आवश्यकता नहीं है"। किसी को भी समझाने की परवाह क्यों?

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

हालांकि कुछ अंतर्निहित धारणाएं हैं:

  • यह मानता है कि आपका आवेदन कक्षा के उदाहरणों की वस्तु पहचान पर कोई अर्थ नहीं रखता है।

  • यह मानता है कि वर्ग अतिभारित हो गया है equalsऔर hashCodeइसलिए कि इन विधियों के अनुसार एक उदाहरण की एक प्रति "मूल" के समान होगी।

या तो या उन दोनों मान्यताओं को गलत माना जा सकता है, और यह एक कॉपी कंस्ट्रक्टर के अतिरिक्त वारंट हो सकता है।


1

इस तरह मैं अपरिवर्तनीय समझता हूं

int a=3;    
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8

अगर int म्यूट कर सकता है, "a" 8 प्रिंट करेगा, लेकिन ऐसा नहीं है क्योंकि यह अपरिवर्तनीय है, यही कारण है कि 3. यह आपका उदाहरण सिर्फ एक नया असाइनमेंट है।


0

मैं स्पष्ट कर सकता हूं कि सरल नमूना कोड द्वारा इंटेगर (और इसके अन्य पंथ जैसे फ्लोट, शॉर्ट आदि) अपरिवर्तनीय हैं:

नमूना कोड

public class Test{
    public static void main(String... args){
        Integer i = 100;
        StringBuilder sb = new StringBuilder("Hi");
        Test c = new Test();
        c.doInteger(i);
        c.doStringBuilder(sb);
        System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
    }

    private void doInteger(Integer i){
        i=1000;
    }

    private void doStringBuilder(StringBuilder sb){
        sb.append(" there");
    }

}

वास्तविक परिणाम

उसका परिणाम अपेक्षित परिणाम के बजाय हाय हाय 100 आता है (दोनों एसबी और मैं परस्पर वस्तुओं के मामले में) हाय वहाँ 1000

यह दिखाता है कि मुख्य रूप से i द्वारा बनाई गई वस्तु को संशोधित नहीं किया गया है, जबकि sb को संशोधित किया गया है।

इसलिए स्ट्रिंगबर्ल ने परस्पर व्यवहार का प्रदर्शन किया लेकिन इंटेगर का नहीं।

तो इंटेगर इम्युटेबल है। इसलिए साबित हुआ

केवल इंटेगर के बिना एक और कोड:

public class Test{
    public static void main(String... args){
        Integer i = 100;
        Test c = new Test();
        c.doInteger(i);
        System.out.println(i); //Expected result is 1000 in case Integer is mutable
    }

    private void doInteger(Integer i){
        i=1000;
    }


}

आप दो अलग-अलग चीजें कर रहे हैं - पूर्णांक को फिर से असाइन करने और स्ट्रिंगर पर एक विधि को कॉल करने की कोशिश कर रहे हैं। यदि आप करते हैं private void doStringBuilder(StringBuilder sb){ sb = new StringBuilder(); }तो sbअपरिवर्तित है।
MT0

मैंने StringBuilder (जो कि उत्परिवर्तनीय है) को जोड़ा, बस एक और वस्तु है जो कि उत्परिवर्तित है, के साथ इंटेक्स को जूसकपोज किया। यदि आप चाहते हैं कि आप सभी StringBuilder से संबंधित कोड हटा सकते हैं और सिर्फ 100 देखने के लिए प्रिंटआउट ले सकते हैं।
आशुतोष निगम

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

कोशिश करेंprivate void doInteger(Integer i){ System.out.println( i == 100 ); i=1000; System.out.println( i == 100 ); }
MT0

@ MT0 जब आप मान से गुजरते हैं तो StringBuilder अभी भी उसी ऑब्जेक्ट की ओर इशारा कर रहा है, लेकिन Integer उसी ऑब्जेक्ट के संदर्भ में नहीं नई कॉपी पास कर रहा है। यदि आप doInteger में प्रिंटआउट लेते हैं, तो आप फ़ंक्शन के पास मौजूद कॉपी को प्रदर्शित कर रहे हैं मुख्य फ़ंक्शन नहीं। हम देखना चाहते हैं कि मेरे द्वारा बताई गई वस्तु समान है या नहीं। आशा है कि यह अवधारणाओं को साफ करता है :) इसके अलावा StringBuilder का अपरिवर्तनीय संस्करण स्ट्रिंग है। मुझे बताएं कि क्या आप चाहते हैं कि मैं इसके लिए एक नमूना साझा करूं।
आशुतोष निगम

-1
public static void main(String[] args) {
    // TODO Auto-generated method stub

    String s1="Hi";
    String s2=s1;

    s1="Bye";

    System.out.println(s2); //Hi  (if String was mutable output would be: Bye)
    System.out.println(s1); //Bye

    Integer i=1000;
    Integer i2=i;

    i=5000;

    System.out.println(i2); // 1000
    System.out.println(i); // 5000

    int j=1000;
    int j2=j;

    j=5000;

    System.out.println(j2); // 1000
    System.out.println(j); //  5000


    char c='a';
    char b=c;

    c='d';

    System.out.println(c); // d
    System.out.println(b); // a
}

आउटपुट है:

हाय बाय 1000 5000 5000 1000 5000 डी

तो चार परस्पर है, स्ट्रिंग इंटेगर और int अपरिवर्तनीय हैं।


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