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




final (12)

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

जावा में हम चर के साथ 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 वास्तव में कैसे काम करता है?


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

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

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


जब आप इसे स्थिर अंतिम बनाते हैं तो इसे स्थिर प्रारंभिक ब्लॉक में प्रारंभ किया जाना चाहिए

    private static final List foo;

    static {
        foo = new ArrayList();
    }

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

जावा में 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


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


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

final कई स्थानों पर इस्तेमाल किया जा सकता है।

  1. कक्षाएं

एक 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 संदर्भ मूल्य का मूल्य बदला नहीं जा सकता है। यानी केवल एक प्रारंभिक अनुमति है। इस परिदृश्य में, रन टाइम में, चूंकि जेआरई जानता है कि मूल्यों को बदला नहीं जा सकता है, यह इन सभी अंतिम मूल्यों (अंतिम संदर्भों) को एल 1 कैश में लोड करता है । क्योंकि इसे मुख्य स्मृति से बार-बार लोड करने की आवश्यकता नहीं है । अन्यथा यह एल 2 कैश में लोड होता है और समय-समय पर मुख्य स्मृति से लोड हो जाता है। तो यह भी एक प्रदर्शन सुधार है।

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


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

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.
    }
}

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

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

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

दृष्टांत 1

private final List foo;  // 1

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

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

परिदृश्य 2

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 अंदर सामग्री जोड़ रहे हैं जिसकी अनुमति है। यदि आप foo संदर्भ चर में एक new ArrayList() असाइन करने का प्रयास करते हैं तो संकलक शिकायत करता है।
नियम यदि आपने final चर प्रारंभ किया है, तो आप इसे किसी भिन्न ऑब्जेक्ट के संदर्भ में नहीं बदल सकते हैं। (इस मामले में ArrayList )

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


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

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

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

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

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

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

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

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


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

foo = new ArrayList();

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

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

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

foo = new ArrayList();

इससे आपको एक संकलन त्रुटि मिल जाएगी।

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

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

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


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

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

public void showCaseFinalArgumentVariable(final int someFinalInt){

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

}

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


final कीवर्ड का उपयोग इस पर निर्भर करते हुए दो अलग-अलग तरीकों से किया जा सकता है:

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

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

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


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

public static final String hello = "Hello";

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

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

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

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

अंतिम पाठ का उपयोग करने के लाभ इस धागे में संबोधित हैं







final