जावा में "अंतिम" कीवर्ड कैसे काम करता है? (मैं अभी भी एक वस्तु को संशोधित कर सकता हूं।)


480

जावा में हम उपयोग करते हैं final कीवर्ड का चर के साथ करते हैं ताकि यह निर्दिष्ट किया जा सके कि इसके मूल्यों को बदलना नहीं है। लेकिन मैं देखता हूं कि आप क्लास के कंस्ट्रक्टर / तरीकों में मूल्य बदल सकते हैं। फिर, यदि चर है staticतो यह एक संकलन त्रुटि है।

यहाँ कोड है:

import java.util.ArrayList;
import java.util.List;

class Test {
  private final List foo;

  public Test()
  {
      foo = new ArrayList();
      foo.add("foo"); // Modification-1
  }
  public static void main(String[] args) 
  {
      Test t = new Test();
      t.foo.add("bar"); // Modification-2
      System.out.println("print - " + t.foo);
  }
}

उपरोक्त कोड ठीक काम करता है और कोई त्रुटि नहीं है।

अब चर को इस प्रकार बदलें static:

private static final List foo;

अब यह एक संकलन त्रुटि है। यह finalवास्तव में कैसे काम करता है ?


चूंकि फू दिखाई नहीं दे रहा है - यह कैसे संकलित कर सकता है?
ब्योर्न हॉलस्ट्रॉम

5
@ ईथरलप्रशांत जो सत्य नहीं है। निजी स्थिर चर मान्य हैं, वे जिस कक्षा में परिभाषित किए गए हैं, उसके अंदर स्थैतिक विधियों से पहुंच योग्य हैं। एक स्थिर चर का मतलब है कि चर एक बार मौजूद है और एक वर्ग के उदाहरण के लिए बाध्य नहीं है।
mbdavis

3
@ शंभवी ओह! धन्यवाद। लेकिन फिर भी मैं उन लोगों की मदद करने के लिए टिप्पणी को नहीं हटाऊंगा जो मेरे जैसे सोच रहे हैं और फिर आपकी टिप्पणी उन्हें सही दिशा में सोचने का मौका देगी।
तत्पश्चात

@ ईथरलप्रशांत ठीक है कोई चिंता नहीं!
mbdavis

जवाबों:


518

आपको हमेशा एक वैरिएबल को इनिशियलाइज़ करने की अनुमति है final। संकलक यह सुनिश्चित करता है कि आप इसे केवल एक बार कर सकते हैं।

ध्यान दें कि एक finalचर में संग्रहित वस्तु पर कॉल करने के तरीकों का शब्दार्थों से कोई लेना-देना नहीं है final। दूसरे शब्दों में: finalकेवल संदर्भ के बारे में है, और संदर्भित वस्तु की सामग्री के बारे में नहीं।

जावा में ऑब्जेक्ट अपरिवर्तनीयता की कोई अवधारणा नहीं है; इस वस्तु को ध्यान से डिजाइन करके हासिल किया जाता है, और यह एक बहुत ही मामूली प्रयास है।


12
t.foo = new ArrayList () करने की कोशिश करें; मुख्य विधि में और आपको संकलन त्रुटि मिलेगी ... संदर्भ फू को ArrayList की सिर्फ एक अंतिम वस्तु से बांधा गया है ... यह किसी भी अन्य ArrayList की ओर इशारा नहीं कर सकता है
Code2Interface

50
हममम। संदर्भ के बारे में इसके सभी मूल्य नहीं हैं। धन्यवाद!
GS

2
मेरा एक सवाल है। किसी को पता है कि मैंने "फाइनल" दावा किया है कि स्टैक पर वेरिएबल को स्टोर किया जा सकता है। क्या ये सही है? मैंने हर जगह खोज की है और ऐसा कोई भी संदर्भ नहीं मिला है जो इस दावे को स्वीकार या अस्वीकृत कर सके। मैंने जावा और एंड्रॉइड दोनों प्रलेखन पर खोज की है। "जावा मेमोरी मॉडल" के लिए भी खोज की। शायद यह C / C ++ पर इस तरह से काम करता है, लेकिन मुझे नहीं लगता कि यह जावा पर इस तरह से काम करता है। क्या मैं सही हूँ?
Android डेवलपर

4
जावा में @androiddeveloper कुछ भी स्पष्ट रूप से स्टैक / हीप प्लेसमेंट को नियंत्रित नहीं कर सकता है। अधिक विशेष रूप से, हॉटस्पॉट जेआईटी कंपाइलर द्वारा तय किए गए स्टैक प्लेसमेंट विश्लेषण से बचने के अधीन है , जो कि एक चर है या नहीं, यह जाँचने से कहीं अधिक शामिल है final। म्यूटेबल ऑब्जेक्ट्स को स्टैक-आबंटित भी किया जा सकता है। finalफ़ील्ड भले ही भागने के विश्लेषण में मदद कर सकती हैं, लेकिन यह काफी अप्रत्यक्ष मार्ग है। यह भी ध्यान दें कि प्रभावी रूप से अंतिम चर के समान finalस्रोत कोड में चिह्नित के समान संधि है ।
मार्को टोपोलनिक

5
finalवर्ग फ़ाइल में मौजूद है और एक अनुकूलन क्रम के लिए महत्वपूर्ण अर्थ परिणाम है। इसकी लागत भी लग सकती है क्योंकि JLS के पास finalकिसी वस्तु के क्षेत्रों की संगति के बारे में एक मजबूत गारंटी है । उदाहरण के लिए, एआरएम प्रोसेसर को एक वर्ग के प्रत्येक कंस्ट्रक्टर के अंत में एक स्पष्ट मेमोरी बैरियर इंस्ट्रक्शन का उपयोग करना चाहिए जिसमें finalफ़ील्ड हैं। अन्य प्रोसेसरों पर, इसकी आवश्यकता नहीं है।
मार्को टोपोलनिक

574

यह एक पसंदीदा साक्षात्कार प्रश्न है । इस सवाल के साथ, साक्षात्कारकर्ता यह पता लगाने की कोशिश करता है कि आप निर्माणकर्ताओं, विधियों, वर्ग चर (स्थिर चर) और उदाहरण चर के संबंध में वस्तुओं के व्यवहार को कितनी अच्छी तरह समझते हैं।

import java.util.ArrayList;
import java.util.List;

class Test {
    private final List foo;

    public Test() {
        foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

    public void setFoo(List foo) {
       //this.foo = foo; Results in compile time error.
    }
}

उपरोक्त मामले में, हमने 'टेस्ट' के लिए एक कंस्ट्रक्टर को परिभाषित किया है और इसे 'सेटफू' विधि दी है।

कंस्ट्रक्टर के बारे में: कंस्ट्रक्टर को कीवर्ड का उपयोग करके केवल एक बार प्रति ऑब्जेक्ट निर्माण के लिए आमंत्रित किया जा सकता है new। आप कई बार कंस्ट्रक्टर को आमंत्रित नहीं कर सकते, क्योंकि कंस्ट्रक्टर ऐसा करने के लिए डिज़ाइन नहीं किया गया है।

विधि के बारे में: एक विधि को जितनी बार चाहें उतनी बार मंगवाया जा सकता है (यहां तक ​​कि कभी नहीं) और संकलक इसे जानता है।

दृष्टांत 1

private final List foo;  // 1

fooएक उदाहरण चर है। जब हम Testक्लास ऑब्जेक्ट बनाते हैं तो इंस्टेंस वेरिएबल foo, Testक्लास के ऑब्जेक्ट के अंदर कॉपी किया जाएगा । यदि हम fooकंस्ट्रक्टर के अंदर असाइन करते हैं , तो कंपाइलर जानता है कि कंस्ट्रक्टर को केवल एक बार ही इनवाइट किया जाएगा, इसलिए कंस्ट्रक्टर के अंदर इसे असाइन करने में कोई समस्या नहीं है।

यदि हम fooकिसी विधि के अंदर असाइन करते हैं , तो संकलक जानता है कि एक विधि को कई बार कहा जा सकता है, जिसका अर्थ है कि मूल्य को कई बार बदलना होगा, जो एक finalचर के लिए अनुमति नहीं है । तो कंपाइलर तय करता है कंस्ट्रक्टर अच्छा विकल्प है! आप केवल एक बार एक अंतिम चर के लिए एक मूल्य प्रदान कर सकते हैं।

दृश्य २

private static final List foo = new ArrayList();

fooअब एक स्थिर चर है। जब हम Testक्लास का एक उदाहरण बनाते हैं , fooतो ऑब्जेक्ट को कॉपी नहीं किया जाएगा क्योंकि fooयह स्थिर है। अब fooप्रत्येक वस्तु का एक स्वतंत्र गुण नहीं है। यह Testवर्ग की संपत्ति है । लेकिन fooकई वस्तुओं द्वारा देखा जा सकता है और यदि प्रत्येक वस्तु जो newकीवर्ड का उपयोग करके बनाई गई है जो अंततः Testनिर्माणकर्ता को आमंत्रित करेगी जो कि कई ऑब्जेक्ट निर्माण के समय मूल्य को बदलता है (याद रखें static fooकि प्रत्येक ऑब्जेक्ट में कॉपी नहीं किया गया है, लेकिन कई ऑब्जेक्ट्स के बीच साझा किया गया है ।)

परिदृश्य 3

t.foo.add("bar"); // Modification-2

ऊपर Modification-2आपके प्रश्न से है। उपरोक्त मामले में, आप पहले संदर्भित ऑब्जेक्ट को नहीं बदल रहे हैं, लेकिन आप उस सामग्री को जोड़ रहे हैं fooजिसके अंदर अनुमति है। संकलक की शिकायत करता है, तो आप एक आवंटित करने के लिए कोशिश new ArrayList()करने के लिए fooसंदर्भ चर।
नियम यदि आपने किसी finalवैरिएबल को इनिशियलाइज़ किया है, तो आप इसे किसी भिन्न ऑब्जेक्ट के संदर्भ में नहीं बदल सकते। (इस मामले में ArrayList)

अंतिम कक्षाओं को उपवर्गित नहीं किया जा सकता है
अंतिम विधियों को ओवरराइड नहीं किया जा सकता है। (यह विधि सुपरक्लास में है)
अंतिम विधियाँ ओवरराइड कर सकती हैं। (इसे व्याकरणिक तरीके से पढ़ें। यह तरीका एक उपवर्ग में है)


1
केवल स्पष्ट करने के लिए। परिदृश्य 2 में आप कह रहे हैं कि fooअंतिम पदनाम के बावजूद कई बार सेट किया जाएगा यदि fooटेस्ट क्लास में सेट किया गया है और टेस्ट के कई उदाहरण बनाए गए हैं?
रॉ

परिदृश्य 2 के लिए अंतिम पंक्ति समझ में नहीं आई: लेकिन fooकई वस्तुएं हो सकती हैं।) क्या इसका मतलब है, अगर मैं एक बार में एक से अधिक ऑब्जेक्ट बनाता हूं, तो अंतिम चर को इनिशियलाइज़ करने वाली कौन सी वस्तु निष्पादन पर निर्भर करती है?
सौम्या सुहागिया

1
मुझे लगता है कि परिदृश्य 3 के बारे में सोचने का एक उपयोगी तरीका है कि क्या आप एक एरियर लेलिस्ट finalद्वारा संदर्भित मेमोरी एड्रेस को असाइन कर रहे हैं foo। आप finalपहले तत्व foo(या उस मामले के लिए किसी भी तत्व) द्वारा संदर्भित मेमोरी पते को असाइन नहीं कर रहे हैं । इसलिए आप बदल नहीं सकते fooलेकिन आप बदल सकते हैं foo[0]
पिंकर्टन

@Rawr जैसा कि यह खड़ा है, परिदृश्य 2 के कारण संकलन-समय त्रुटि होगी foo = new ArrayList();- fooस्थैतिक चर को संदर्भित करता है क्योंकि हम उसी वर्ग के अंदर हैं।
flow2k

मैं जावा सीखने वाला C ++ डेवलपर हूं। क्या C ++ में कीवर्ड finalके समान वैरिएबल पर सोचना सुरक्षित है const?
डग बारबिएरी

213

अंतिम कीवर्ड का उपयोग करने का कई तरीका है:

  • एक अंतिम वर्ग को उपवर्गित नहीं किया जा सकता है।
  • एक अंतिम विधि उपवर्गों द्वारा ओवरराइड नहीं की जा सकती है
  • एक अंतिम चर को केवल एक बार शुरू किया जा सकता है

अन्य उपयोग:

  • जब एक अनाम आंतरिक वर्ग को एक विधि के शरीर के भीतर परिभाषित किया जाता है, तो उस विधि के दायरे में अंतिम घोषित सभी चर भीतर के वर्ग से सुलभ होते हैं

एक स्थिर वर्ग चर जेवीएम की शुरुआत से मौजूद होगा, और इसे कक्षा में आरंभीकृत किया जाना चाहिए। यदि आप ऐसा करते हैं तो त्रुटि संदेश प्रकट नहीं होगा।


24
यह अब तक का मेरा पसंदीदा जवाब है। सरल और सीधे-आगे, यह वही है जो मैं जावा के बारे में ऑनलाइन डॉक्स में पढ़ने की उम्मीद करूंगा।
रैंडर्स ०३

स्थैतिक चर में हम जितनी बार चाहें उतनी बार आरंभीकरण कर सकते हैं?
जॉर्ज सार्इवा

1
@jorgesaraiva हाँ, स्थिर चर स्थिरांक नहीं हैं।
czupe

1
@jorgesaraiva आप कर सकते हैं आवंटित (नहीं इनिशियलाइज़ ) static(जब तक वे नहीं हैं क्षेत्रों final) कई बार के रूप में आप चाहते हैं। असाइनमेंट और इनिशियलाइज़ेशन के बीच के अंतर के लिए इस विकी को देखें ।

56

finalकीवर्ड दो अलग-अलग के आधार पर तरीके से व्याख्या की जा सकती है, क्या इस पर किया जाता है:

मूल्य प्रकार: के लिए intहै, doubleरों आदि, यह सुनिश्चित करेंगे कि मूल्य नहीं बदल सकते,

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

जैसे, final List<Whatever> foo;यह सुनिश्चित करता है कि fooहमेशा एक ही सूची को संदर्भित करता है , लेकिन समय के साथ उक्त सूची की सामग्री बदल सकती है।


23

यदि आप fooस्थैतिक बनाते हैं , तो आपको निम्न उदाहरणों की तरह इसे क्लास कंस्ट्रक्टर (या इनलाइन जहां आप इसे परिभाषित करते हैं) में इनिशियलाइज़ करना होगा।

क्लास कंस्ट्रक्टर (उदाहरण नहीं):

private static final List foo;

static
{
   foo = new ArrayList();
}

पंक्ति में:

private static final List foo = new ArrayList();

यहां समस्या यह नहीं है कि finalसंशोधक कैसे काम करता है, बल्कि यह भी है कि staticसंशोधक कैसे काम करता है।

finalसंशोधक समय के आधार पर आपके निर्माता पूर्ण करता कॉल (यानी आप निर्माता में यह प्रारंभ करना होगा) आपके संदर्भ के प्रारंभ लागू करता है।

जब आप किसी विशेषता को प्रारंभ करते हैं, तो यह उस कोड से पहले आरंभीकृत हो जाता है, जिसे आपने कंस्ट्रक्टर के लिए निर्धारित किया है, जिसे चलाया जाता है, इसलिए आपको निम्नलिखित परिणाम मिलते हैं:

  • यदि fooहै static, तो आपके द्वारा अपनी कक्षा के लिए निर्धारित किए foo = new ArrayList()गए static{}कंस्ट्रक्टर से पहले निष्पादित किया जाएगा
  • यदि fooनहीं static, तो foo = new ArrayList()आपके कंस्ट्रक्टर को चलाने से पहले निष्पादित किया जाएगा

जब आप किसी विशेषता-इन-लाइन को सम्मिलित नहीं करते हैं, तो finalसंशोधक लागू करता है कि आप इसे प्रारंभ करते हैं और आपको निर्माणकर्ता में ऐसा करना चाहिए। यदि आपके पास एक staticसंशोधक भी है , तो निर्माणकर्ता को आपको वर्ग 'इनिशियलाइज़ेशन ब्लॉक' में विशेषता को इनिशियलाइज़ करना होगा:static{} :।

आपके कोड में आपको जो त्रुटि मिलती है, वह इस तथ्य से है कि static{}जब क्लास लोड की जाती है, तो उस समय से पहले जब आप उस क्लास की किसी वस्तु को इंस्टेंट करते हैं। इस प्रकार, fooजब कक्षा बनाई जाती है , तो आपने प्रारंभ नहीं किया होगा ।

static{}ब्लॉक को एक प्रकार की वस्तु के लिए एक निर्माता के रूप में सोचें Class। यह वह जगह है जहाँ आपको अपनी static finalश्रेणी के गुणों का आरंभीकरण अवश्य करना चाहिए (यदि इनलाइन नहीं किया गया है)।

पक्षीय लेख:

finalसंशोधक भरोसा दिलाते const सत्ता केवल आदिम प्रकार और संदर्भ के लिए।

जब आप एक finalवस्तु घोषित करते हैं , तो आपको जो मिलता है वह एक final संदर्भ है , वह उस वस्तु का होता है, लेकिन वस्तु स्वयं स्थिर नहीं होती है।

क्या तुम सच में जब एक घोषित प्राप्त कर रहे हैं finalकि विशेषता है, एक बार आप (तरह अपने विशिष्ट प्रयोजन के लिए एक वस्तु की घोषणा final Listहै कि आप घोषणा की है), कि और केवल उस वस्तु उस उद्देश्य के लिए उपयोग किया जाएगा: आप नहीं कर परिवर्तन करने के लिए किया जाएगा List fooकरने के लिए एक और List, लेकिन आप अभी भी Listआइटम जोड़कर / हटाकर अपने को बदल सकते हैं ( Listआप जो उपयोग कर रहे हैं वही होगा, केवल इसकी सामग्री बदल दी गई है)।


8

यह एक बहुत अच्छा साक्षात्कार प्रश्न है। कभी-कभी वे आपसे यह भी पूछ सकते हैं कि अंतिम वस्तु और अपरिवर्तनीय वस्तु में क्या अंतर है।

1) जब कोई अंतिम वस्तु का उल्लेख करता है, तो इसका मतलब है कि संदर्भ को नहीं बदला जा सकता है, लेकिन इसकी स्थिति (उदाहरण के चर) को बदला जा सकता है।

2) एक अपरिवर्तनीय वस्तु वह है जिसकी स्थिति को बदला नहीं जा सकता है, लेकिन इसके संदर्भ को बदला जा सकता है। उदाहरण के लिए:

    String x = new String("abc"); 
    x = "BCG";

रेफ चर x को एक अलग स्ट्रिंग को इंगित करने के लिए बदला जा सकता है, लेकिन "एबीसी" के मूल्य को नहीं बदला जा सकता है।

3) इंस्टेंस वेरिएबल्स (नॉन स्टैटिक फील्ड्स) को इनिशियलाइज़ किया जाता है जब कंस्ट्रक्टर कहा जाता है। इसलिए आप एक कंस्ट्रक्टर के अंदर वैरिएबल के मानों को इनिशियलाइज़ कर सकते हैं।

4) "लेकिन मैं देखता हूं कि आप क्लास के कंस्ट्रक्टर / तरीकों में मूल्य बदल सकते हैं"। - आप इसे किसी विधि के अंदर नहीं बदल सकते।

5) क्लास लोडिंग के दौरान एक स्टैटिक वेरिएबल इनिशियलाइज़ होता है। इसलिए आप किसी कंस्ट्रक्टर के अंदर इनिशियलाइज़ नहीं कर सकते, इसे पहले भी किया जाना चाहिए। इसलिए आपको घोषणा के दौरान एक स्थिर वैरिएबल को मान असाइन करने की आवश्यकता है।


7

finalजावा में कीवर्ड उपयोगकर्ता को प्रतिबंधित करने के लिए किया जाता है। जावा finalकीवर्ड का उपयोग कई संदर्भों में किया जा सकता है। अंतिम हो सकता है:

  1. परिवर्तनशील
  2. तरीका
  3. कक्षा

finalकीवर्ड, चर के साथ लागू किया जा सकता एक final, चर कोई मूल्य नहीं है कि खाली कहा जाता है finalचर या अप्रारंभीकृत finalचर। इसे कंस्ट्रक्टर में ही इनिशियलाइज़ किया जा सकता है। रिक्त finalचर staticभी हो सकता है जिसे staticकेवल ब्लॉक में आरंभीकृत किया जाएगा ।

जावा अंतिम चर:

आप किसी भी चर के रूप में करते हैं final, तो आप मूल्य बदल नहीं सकते की finalचर (यह निरंतर हो जाएगा)।

finalचर का उदाहरण

एक अंतिम चर गतिमान है, हम इस चर के मूल्य को बदलने जा रहे हैं, लेकिन इसे बदला नहीं जा सकता क्योंकि अंतिम चर को एक बार निर्दिष्ट मान कभी नहीं बदला जा सकता है।

class Bike9{  
    final int speedlimit=90;//final variable  
    void run(){  
        speedlimit=400;  // this will make error
    }  

    public static void main(String args[]){  
    Bike9 obj=new  Bike9();  
    obj.run();  
    }  
}//end of class  

जावा अंतिम वर्ग:

यदि आप किसी भी वर्ग को बनाते हैं final, तो आप इसे विस्तारित नहीं कर सकते

अंतिम वर्ग का उदाहरण

final class Bike{}  

class Honda1 extends Bike{    //cannot inherit from final Bike,this will make error
  void run(){
      System.out.println("running safely with 100kmph");
   }  

  public static void main(String args[]){  
      Honda1 honda= new Honda();  
      honda.run();  
      }  
  }  

जावा अंतिम विधि:

यदि आप किसी भी विधि को अंतिम बनाते हैं, तो आप उसे ओवरराइड नहीं कर सकते।

finalहोंडा में विधि का तरीका (रन) बाइक में नहीं चला सकता ()

class Bike{  
  final void run(){System.out.println("running");}  
}  

class Honda extends Bike{  
   void run(){System.out.println("running safely with 100kmph");}  

   public static void main(String args[]){  
   Honda honda= new Honda();  
   honda.run();  
   }  
}  

से साझा किया गया: http://www.javatpoint.com/final-keyword


7

कुछ सीधी परिभाषाओं का उल्लेख करने के लिए लायक:

वर्ग / विधि

आप कुछ या सभी वर्ग विधियों को घोषित कर सकते हैं final, ताकि यह इंगित किया जा सके कि उपवर्गों द्वारा विधि को ओवरराइड नहीं किया जा सकता है।

चर

एक बार जब एक finalवैरिएबल को इनिशियलाइज़ किया जाता है, तो इसमें हमेशा समान मूल्य होता है।

final मूल रूप से मामले के आधार पर किसी भी चीज (उपवर्ग, चर "पुनर्मूल्यांकन") को अधिलेखित / अधिलेखित करने से बचें।


1
मुझे लगता है कि चर के बारे में अंतिम परिभाषा थोड़ी कम है; "जावा में, जब अंतिम कीवर्ड का उपयोग आदिम डेटा प्रकारों (चर, फ़्लोट, .. आदि) के चर के साथ किया जाता है, तो चर का मान नहीं बदला जा सकता है लेकिन जब अंतिम का उपयोग गैर-आदिम चर के साथ किया जाता है (ध्यान दें कि गैर-आदिम चर हमेशा जावा में वस्तुओं के संदर्भ में होते हैं), संदर्भित ऑब्जेक्ट के सदस्यों को बदला जा सकता है। गैर-आदिम चर के लिए अंतिम का मतलब सिर्फ इतना है कि उन्हें किसी अन्य वस्तु को संदर्भित करने के लिए नहीं बदला जा सकता है "। geeksforgeeks.org/g-fact-48
ceyun

यह भी मान्य है, विशेष रूप से आदिम और गैर-आदिम मामलों के रूप में उल्लेख करने के लिए। टी.के.एस।
ivanleoncz

4

finalउपयोगकर्ता को प्रतिबंधित करने के लिए जावा में एक आरक्षित कीवर्ड है और इसे सदस्य चर, विधियों, वर्ग और स्थानीय चर पर लागू किया जा सकता है। अंतिम चर को अक्सर staticजावा में कीवर्ड के साथ घोषित किया जाता है और उन्हें स्थिरांक के रूप में माना जाता है। उदाहरण के लिए:

public static final String hello = "Hello";

जब हम finalकीवर्ड को एक चर घोषणा के साथ उपयोग करते हैं , तो उस चर के अंदर संग्रहीत मूल्य को बाद में नहीं बदला जा सकता है।

उदाहरण के लिए:

public class ClassDemo {
  private final int var1 = 3;
  public ClassDemo() {
    ...
  }
}

नोट : अंतिम के रूप में घोषित एक वर्ग को बढ़ाया या विरासत में नहीं दिया जा सकता है (यानी, सुपर क्लास का उपवर्ग नहीं हो सकता है)। यह नोट करना भी अच्छा है कि अंतिम घोषित किए गए तरीके उपवर्गों द्वारा ओवरराइड नहीं किए जा सकते।

अंतिम सूत्र का उपयोग करने के लाभ इस धागे में दिए गए हैं


2
the value stored inside that variable cannot be changed latterआंशिक रूप से सच है। यह केवल आदिम डेटा प्रकारों के लिए सही है। किसी भी वस्तु के मामले में final, सरणी सूची की तरह, इसका मूल्य बदल सकता है, लेकिन संदर्भ नहीं। धन्यवाद!
GS

3

मान लीजिए कि आपके पास दो मनीबॉक्स हैं, लाल और सफेद। आप इन मनीबॉक्स को केवल दो बच्चों को सौंपते हैं और उन्हें अपने बक्से को इंटरचेंज करने की अनुमति नहीं है। इसलिए आपके पास लाल या सफेद मनीबॉक्स (अंतिम) है जिसे आप बॉक्स को संशोधित नहीं कर सकते हैं लेकिन आप अपने बॉक्स पर पैसा लगा सकते हैं। कोई भी परवाह नहीं करता (संशोधन -2)।


2

सभी उत्तर पढ़ें।

एक अन्य उपयोगकर्ता का मामला है जहां finalकीवर्ड का उपयोग विधि तर्क में किया जा सकता है:

public void showCaseFinalArgumentVariable(final int someFinalInt){

   someFinalInt = 9; // won't compile as the argument is final

}

चर के लिए इस्तेमाल किया जा सकता है जिसे बदला नहीं जाना चाहिए।


1

जब आप इसे स्टैटिक फाइनल करते हैं तो इसे इनिशियल इनिशियलाइज़ेशन ब्लॉक में इनिशियलाइज़ किया जाना चाहिए

    private static final List foo;

    static {
        foo = new ArrayList();
    }

    public Test()
    {
//      foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

1

finalकीवर्ड इंगित करता है कि एक चर केवल एक बार प्रारंभ किया जा सकता है। आपके कोड में आप केवल फाइनल का एक इनिशियलाइज़ेशन कर रहे हैं ताकि शर्तें संतुष्ट हों। यह कथन अकेला इनिशियलाइज़ेशन करता है foo। ध्यान दें final! = अपरिवर्तनीय, इसका केवल यह अर्थ है कि संदर्भ परिवर्तित नहीं हो सकता।

foo = new ArrayList();

जब आप की घोषणा fooके रूप में static finalचर जब वर्ग भरी हुई है प्रारंभ किया जाना चाहिए और इन्स्टेन्शियशन पर भरोसा नहीं कर सकते (उर्फ निर्माता के लिए कहते हैं) प्रारंभ करने fooके बाद से स्थिर क्षेत्रों एक वर्ग का एक उदाहरण के बिना उपलब्ध होना चाहिए। इस बात की कोई गारंटी नहीं है कि स्थिर क्षेत्र का उपयोग करने से पहले निर्माणकर्ता को बुलाया जाएगा।

जब आप के तहत अपने विधि पर अमल static finalपरिदृश्य Testवर्ग instantiating से पहले भरी हुई है tइस समय का कोई इन्स्टेन्शियशन है fooजिसका अर्थ यह तो प्रारंभ नहीं किया गया है fooसभी वस्तुओं है जिसके लिए डिफ़ॉल्ट के लिए सेट है nullNullPointerExceptionजब आप सूची में कोई आइटम जोड़ने का प्रयास करते हैं तो इस बिंदु पर मुझे लगता है कि आपका कोड फेंकता है ।


1

सबसे पहले, आपके कोड में वह स्थान जहाँ आप इनिशियलाइज़ कर रहे हैं (यानी पहली बार असाइन करना) foo यहाँ है:

foo = new ArrayList();

foo एक ऑब्जेक्ट है (टाइप लिस्ट के साथ) इसलिए यह एक रेफरेंस टाइप है, न कि वैल्यू टाइप (जैसे इंट)। जैसे, यह एक मेमोरी लोकेशन (जैसे 0xA7D2A834) का संदर्भ रखता है, जहां आपके लिस्ट एलिमेंट्स को स्टोर किया जाता है। इस तरह की लाइनें

foo.add("foo"); // Modification-1

फू के मूल्य को न बदलें (जो, फिर से, एक स्मृति स्थान का एक संदर्भ है)। इसके बजाय, वे केवल उस संदर्भित मेमोरी स्थान में तत्व जोड़ते हैं। अंतिम कीवर्ड का उल्लंघन करने के लिए , आपको फिर से निम्नानुसार फू को फिर से असाइन करने का प्रयास करना होगा:

foo = new ArrayList();

यही कारण है कि होगा यदि आप एक संकलन त्रुटि दे।


अब, उस तरह से, जब आप स्थैतिक कीवर्ड जोड़ते हैं तो क्या होता है, इसके बारे में सोचें ।

जब आपके पास स्थैतिक कीवर्ड नहीं होता है, तो प्रत्येक ऑब्जेक्ट जो क्लास को इंस्टेंट करता है, उसके पास foo की अपनी प्रति है। इसलिए, कंस्ट्रक्टर फू चर की एक रिक्त, ताज़ा प्रति के लिए एक मूल्य प्रदान करता है, जो पूरी तरह से ठीक है।

हालाँकि, जब आपके पास स्टैटिक कीवर्ड होता है, तो मेमोरी में केवल एक foo मौजूद होता है जो क्लास के साथ जुड़ा होता है। यदि आप दो या दो से अधिक ऑब्जेक्ट बनाने के लिए थे, तो कंस्ट्रक्टर फिर से असाइन करने का प्रयास करेगा कि हर बार अंतिम कीवर्ड का उल्लंघन हो ।


1
  1. चूंकि अंतिम चर गैर-स्थिर है, इसलिए इसे कंस्ट्रक्टर में आरंभीकृत किया जा सकता है। लेकिन अगर आप इसे स्थिर बनाते हैं तो इसे कंस्ट्रक्टर द्वारा आरंभ नहीं किया जा सकता (क्योंकि कंस्ट्रक्टर स्थिर नहीं हैं)।
  2. सूची को अंतिम सूची बनाने से रोकने की उम्मीद नहीं है। finalसिर्फ विशेष वस्तु के संदर्भ को बांधता है। आप उस वस्तु की 'स्थिति' को बदलने के लिए स्वतंत्र हैं, लेकिन स्वयं वस्तु नहीं।

1

निम्नलिखित विभिन्न संदर्भ हैं जहां अंतिम का उपयोग किया जाता है।

अंतिम चर एक अंतिम चर केवल एक बार सौंपा जा सकता है। यदि चर एक संदर्भ है, तो इसका मतलब है कि चर को किसी अन्य वस्तु के संदर्भ में फिर से बांधा नहीं जा सकता है।

class Main {
   public static void main(String args[]){
      final int i = 20;
      i = 30; //Compiler Error:cannot assign a value to final variable i twice
   }
}

अंतिम चर को बाद में मान दिया जा सकता है (घोषित किए जाने पर एक मान निर्दिष्ट करने के लिए अनिवार्य नहीं), लेकिन केवल एक बार।

अंतिम कक्षाएं एक अंतिम वर्ग बढ़ाया नहीं जा सकता (विरासत में मिला)

final class Base { }
class Derived extends Base { } //Compiler Error:cannot inherit from final Base

public class Main {
   public static void main(String args[]) {
   }
}

अंतिम विधियाँ उपवर्गों द्वारा अंतिम विधि को ओवरराइड नहीं किया जा सकता है।

//Error in following program as we are trying to override a final method.
class Base {
  public final void show() {
       System.out.println("Base::show() called");
    }
}     
class Derived extends Base {
    public void show() {  //Compiler Error: show() in Derived cannot override
       System.out.println("Derived::show() called");
    }
}     
public class Main {
    public static void main(String[] args) {
        Base b = new Derived();;
        b.show();
    }
}

1

मैंने यहां एक अद्यतन और गहराई से उत्तर लिखने के बारे में सोचा।

final कीवर्ड का उपयोग कई स्थानों पर किया जा सकता है।

  1. कक्षाएं

A का final classअर्थ है कि कोई भी अन्य वर्ग उस अंतिम वर्ग का विस्तार नहीं कर सकता है । जब जावा रन टाइम ( जेआरई ) जानता है कि एक ऑब्जेक्ट संदर्भ एक अंतिम वर्ग (एफ) के प्रकार में है, तो यह जानता है कि उस संदर्भ का मूल्य केवल एफ के प्रकार में हो सकता है।

उदाहरण के लिए:

F myF;
myF = new F();    //ok
myF = someOther;  //someOther cannot be in type of a child class of F.
                  //because F cannot be extended.

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

  1. तरीकों

final methodकिसी भी वर्ग के ए का मतलब है कि उस वर्ग का विस्तार करने वाला कोई भी बच्चा वर्ग उस अंतिम विधि (एस) को ओवरराइड नहीं कर सकता है । तो इस परिदृश्य में रन टाइम व्यवहार भी कक्षाओं के लिए मेरे द्वारा बताए गए पिछले व्यवहार के साथ काफी समान है।

  1. फ़ील्ड, स्थानीय चर, विधि पैरामीटर

यदि कोई उपरोक्त किसी भी प्रकार का निर्दिष्ट करता है final, तो इसका मतलब है कि मूल्य पहले से ही अंतिम रूप दिया गया है, इसलिए मूल्य को बदला नहीं जा सकता है

उदाहरण के लिए:

खेतों के लिए, स्थानीय मापदंडों

final FinalClass fc = someFC; //need to assign straight away. otherwise compile error.
final FinalClass fc; //compile error, need assignment (initialization inside a constructor Ok, constructor can be called only once)
final FinalClass fc = new FinalClass(); //ok
fc = someOtherFC; //compile error
fc.someMethod(); //no problem
someOtherFC.someMethod(); //no problem

विधि मापदंडों के लिए

void someMethod(final String s){
    s = someOtherString; //compile error
}

इसका सीधा सा अर्थ है कि finalसंदर्भ मूल्य को बदला नहीं जा सकता है। यानी केवल एक इनिशियलाइज़ेशन की अनुमति है। इस परिदृश्य में, रन टाइम में, क्योंकि JRE जानता है कि मानों को बदला नहीं जा सकता है, यह इन सभी अंतिम मानों (अंतिम संदर्भों) को L1 कैश में लोड करता है । क्योंकि इसे मुख्य मेमोरी से बार-बार लोड करने की आवश्यकता नहीं होती है । अन्यथा यह L2 कैश पर लोड होता है और मुख्य मेमोरी से समय-समय पर लोड होता है। तो यह एक प्रदर्शन में सुधार भी है।

इसलिए उपरोक्त 3 परिदृश्यों में, जब हमने उन finalस्थानों पर कीवर्ड निर्दिष्ट नहीं किए हैं जिनका हम उपयोग कर सकते हैं, तो हमें चिंता करने की आवश्यकता नहीं है, कंपाइलर अनुकूलन हमारे लिए ऐसा करेंगे। कई अन्य चीजें भी हैं जो संकलक अनुकूलन हमारे लिए करते हैं। :)


0

सबसे ऊपर सही हैं। इसके अलावा यदि आप नहीं चाहते कि अन्य लोग आपकी कक्षा से उप कक्षाएं बनाएँ, तो अपनी कक्षा को अंतिम घोषित करें। फिर यह आपके वर्ग वृक्ष पदानुक्रम का पत्ती स्तर बन जाता है कि कोई भी इसे आगे नहीं बढ़ा सकता है। वर्गों के विशाल पदानुक्रम से बचने के लिए यह एक अच्छा अभ्यास है।

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