नमस्ते! आप "संशोधक" शब्द से पहले से ही परिचित हैं। कम से कम, आपने एक्सेस संशोधक (सार्वजनिक, निजी) और स्थैतिक संशोधक का सामना किया है। आज हम final नामक एक विशेष संशोधक पर चर्चा करेंगे । आप हमारे कार्यक्रम के अंतिम संशोधक "सीमेंट" भागों को कह सकते हैं जहां निरंतर, स्पष्ट, अपरिवर्तनीय व्यवहार की आवश्यकता होती है। आपके प्रोग्राम में तीन स्थान हैं जिनका आप उपयोग कर सकते हैं: क्लासेस, मेथड्स और वेरिएबल्स। आइए उनके माध्यम से क्रम में चलते हैं। यदि अंतिम संशोधक का उपयोग वर्ग घोषणा में किया जाता है, तो इसका मतलब है कि वर्ग को विरासत में नहीं मिला जा सकता है। पिछले पाठों में, हमने एक साधारण वंशानुक्रम उदाहरण का उपयोग किया: हमारे पास एक
Animal
मूल वर्ग और दो बाल वर्ग थे: Cat
औरDog
public class Animal {
}
public class Cat extends Animal {
// Fields and methods of the Cat class
}
public class Dog extends Animal {
// Fields and methods of the Dog class
}
हालांकि, अगर हम कक्षा पर अंतिमAnimal
संशोधक का उपयोग करते हैं , तो Cat
और Dog
कक्षाएं इसे प्राप्त नहीं कर सकती हैं।
public final class Animal {
}
public class Cat extends Animal {
// Error! Cannot inherit from final Animal
}
कंपाइलर तुरंत एक त्रुटि उत्पन्न करता है। जावा में, कई अंतिम कक्षाएं पहले ही लागू हो चुकी हैं। उनमें से आप अक्सर उपयोग करते हैं, String
सबसे प्रसिद्ध है। इसके अलावा, यदि किसी वर्ग को अंतिम घोषित किया जाता है , तो कक्षा के सभी तरीके भी अंतिम हो जाते हैं । इसका क्या मतलब है? यदि अंतिम संशोधक का उपयोग करके एक विधि घोषित की जाती है , तो आप उस विधि को ओवरराइड नहीं कर सकते। उदाहरण के लिए, यहां हमारे पास एक Animal
वर्ग है जो एक speak()
विधि घोषित करता है। लेकिन, कुत्ते और बिल्लियाँ निश्चित रूप से अलग-अलग तरीकों से "बोलते" हैं। इसलिए, हम दोनों Cat
और Dog
कक्षाओं में स्पीक () विधियों की घोषणा करेंगे, लेकिन हम उन्हें अलग तरीके से लागू करेंगे।
public class Animal {
public void speak() {
System.out.println("Hello!");
}
}
public class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow!");
}
}
public class Dog extends Animal {
@Override
public void speak() {
System.out.println("Woof!");
}
}
हमने Cat
और Dog
कक्षाओं को मूल वर्ग में घोषित विधि को ओवरराइड कर दिया है। अब, एक जानवर अलग तरह से बोलेगा, यह इस बात पर निर्भर करता है कि वह किस प्रकार की वस्तु है:
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
cat.speak();
dog.speak();
}
}
आउटपुट: म्याऊ! वाह! हालाँकि, यदि हम Animal
कक्षा की speak()
विधि को अंतिम घोषित करते हैं, तो हम इसे अन्य वर्गों में ओवरराइड नहीं कर सकते हैं:
public class Animal {
public final void speak() {
System.out.println("Hello!");
}
}
public class Cat extends Animal {
@Override
public void speak() {// Error! A final method can't be overridden!
System.out.println("Meow!");
}
}
speak()
और हमारी वस्तुओं को मूल वर्ग में परिभाषित विधि का उपयोग करने के लिए मजबूर किया जाएगा :
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
cat.speak();
dog.speak();
}
आउटपुट: हैलो! नमस्ते! अब, अंतिम चर के संबंध में। उन्हें स्थिरांक के रूप में भी जाना जाता है । सबसे पहले (और सबसे महत्वपूर्ण), एक स्थिर मान को निर्दिष्ट प्रारंभिक मान बदला नहीं जा सकता। यह एक बार और सभी के लिए सौंपा गया है।
public class Main {
private static final int CONSTANT_EXAMPLE = 333;
public static void main(String[] args) {
CONSTANT_EXAMPLE = 999;// Error! You can't assign a new value to a final variable!
}
}
एक स्थिरांक को तुरंत प्रारंभ करने की आवश्यकता नहीं है। यह बाद में किया जा सकता है। लेकिन, शुरू में इसे दिया गया मान हमेशा के लिए एक जैसा रहेगा।
public static void main(String[] args) {
final int CONSTANT_EXAMPLE;
CONSTANT_EXAMPLE = 999;// This is allowed
}
दूसरा, हमारे वेरिएबल का नाम नोट करें। जावा में स्थिरांक के लिए भिन्न नामकरण परिपाटी है। यह सामान्य कैमलकेस नोटेशन नहीं है। यदि यह एक सामान्य चर होता, तो हम इसे निरंतर उदाहरण कहते. लेकिन, स्थिरांक के नाम सभी बड़े अक्षरों में लिखे जाते हैं, शब्दों के बीच अंडरस्कोर (यदि एक से अधिक शब्द हैं), उदाहरण के लिए "CONSTANT_EXAMPLE"। हमें स्थिरांक की आवश्यकता क्यों है? वे बहुत उपयोगी हैं यदि, उदाहरण के लिए, एक निश्चित मूल्य है जिसे आप नियमित रूप से किसी प्रोग्राम में उपयोग करते हैं। उदाहरण के लिए, आपने इतिहास बनाने और गेम "द विचर 4" लिखने का निर्णय लिया है। खेल स्पष्ट रूप से नियमित रूप से नायक के नाम का उपयोग करेगा: "गेराल्ट ऑफ रिविया"। यह स्ट्रिंग (और अन्य नायकों के नाम) एक स्थिरांक के रूप में सबसे अच्छा घोषित किया जाता है: इसका मान एक स्थान पर संग्रहीत किया जाएगा, और आप इसे एक लाख बार दर्ज करते समय निश्चित रूप से टाइपो नहीं करेंगे।
public class TheWitcher4 {
private static final String GERALT_NAME = "Geralt of Rivia";
private static final String YENNEFER_NAME = "Yennefer of Wengerberg";
private static final String TRISS_NAME = "Triss Merigold";
public static void main(String[] args) {
System.out.println("The Witcher 4");
System.out.println("It's already the fourth Witcher game, but " + GERALT_NAME + " still can't decide who" +
" he likes more: " + YENNEFER_NAME + " or " + TRISS_NAME);
System.out.println("But, if you've never played The Witcher before, we'll start from the beginning.");
System.out.println("The protagonist's name is " + GERALT_NAME);
System.out.println(GERALT_NAME + " is a witcher, a monster hunter");
}
}
आउटपुट: द विचर 4 यह पहले से ही चौथा विचर गेम है, लेकिन रिविया का गेराल्ट अभी भी यह तय नहीं कर सकता है कि वह किसे अधिक पसंद करता है: वेंगरबर्ग के येनिफर या ट्रिस मैरीगोल्ड लेकिन, अगर आपने पहले कभी द विचर नहीं खेला है, तो हम शुरू करेंगे शुरुआत। नायक का नाम रिविया का गेराल्ट है रिविया का गेराल्ट एक विचर, एक राक्षस शिकारी है हमने नायकों के नामों को स्थिरांक के रूप में घोषित किया है। अब हम निश्चित रूप से कोई टाइपो नहीं बनाएंगे, और उन्हें हर बार हाथ से लिखने की कोई आवश्यकता नहीं है। एक और प्लस: यदि हमें कभी भी पूरे प्रोग्राम में वेरिएबल के मान को बदलने की आवश्यकता होती है, तो आप इसे पूरे कोड बेस में मैन्युअल रूप से संशोधित करने के बजाय एक ही स्थान पर कर सकते हैं। :)
अपरिवर्तनीय प्रकार
जैसा कि आपने जावा के साथ काम किया है, आप शायद पहले से ही इस विचार के अभ्यस्त हो गए हैं कि प्रोग्रामर का सभी वस्तुओं की स्थिति पर लगभग पूर्ण नियंत्रण है। यदि आप कोई वस्तु बनाना चाहते हैंCat
, तो आप कर सकते हैं। यदि आप इसका नाम बदलना चाहते हैं, तो आप कर सकते हैं। अगर आप इसकी उम्र या कुछ और बदलना चाहते हैं, तो आप कर सकते हैं। लेकिन जावा में कई डेटा प्रकार होते हैं जिनमें एक विशेष गुण होता है। वे अपरिवर्तनीय हैं । यदि कोई वर्ग अपरिवर्तनीय है, तो उसकी वस्तुओं की स्थिति को बदला नहीं जा सकता। कुछ उदाहरण चाहते हैं? यह आपको आश्चर्यचकित कर सकता है, लेकिन सबसे प्रसिद्ध अपरिवर्तनीय वर्ग स्ट्रिंग है! तो, हम वास्तव में स्ट्रिंग के मान को नहीं बदल सकते हैं? खैर, कोशिश करते हैं:
public static void main(String[] args) {
String str1 = "I love Java";
String str2 = str1;// Both reference variables point to the same string.
System.out.println(str2);
str1 = "I love Python";// but changing str1 has no impact on str2
System.out.println(str2);// str2 continues to point to the "I love Java" string, but str1 now points to a different object
}
आउटपुट: मुझे जावा से प्यार है मुझे जावा से प्यार है हमारे लिखने के बाद
str1 = "I love Python";
स्ट्रिंग "I love Java"
ऑब्जेक्ट नहीं बदला या कहीं नहीं गया। यह अभी भी खुशी से मौजूद है और इसमें पहले जैसा ही पाठ है। कोड
str1 = "I love Python";
बस एक और वस्तु बनाई, जो अब str1 की ओर इशारा करती है। लेकिन, हमें "आई लव जावा" स्ट्रिंग ऑब्जेक्ट पर कोई प्रभाव नहीं दिख रहा है। ठीक है, चलो कुछ और कोशिश करते हैं! वर्ग String
विधियों से भरा है, और उनमें से कुछ वस्तु की स्थिति को बदलते हुए दिखाई देते हैं! replace()
उदाहरण के लिए, एक तरीका है । आइए हमारी स्ट्रिंग में "जावा" शब्द को "पायथन" में बदलें!
public static void main(String[] args) {
String str1 = "I love Java";
String str2 = str1;// Both reference variables point to the same string.
System.out.println(str2);
str1.replace("Java", "Python");// We try to change the state of str1 by swapping the word "Java" with "Python"
System.out.println(str2);
}
आउटपुट: मुझे जावा से प्यार है मुझे जावा से प्यार है यह फिर से काम नहीं करता! शायद बदलें विधि काम नहीं करती है? आइए कुछ और प्रयास करें। उदाहरण के लिए substring()
,। यह तर्कों के रूप में पारित चरित्र सूचकांकों के आधार पर एक सबस्ट्रिंग देता है। आइए हमारी स्ट्रिंग के पहले 10 अक्षर काट दें:
public static void main(String[] args) {
String str1 = "I love Java";
String str2 = str1;// Both reference variables point to the same string.
System.out.println(str2);
str1.substring(10);// Truncate the original String
System.out.println(str2);
}
आउटपुट: मुझे जावा से प्यार है मुझे जावा से प्यार है कुछ भी नहीं बदला। और यह नहीं होना चाहिए। जैसा कि हमने पहले कहा, स्ट्रिंग्स अपरिवर्तनीय हैं। तो, कक्षा में सभी विधियों के साथ क्या है String
? आखिरकार, वे तार काट सकते हैं, वर्ण बदल सकते हैं, और बहुत कुछ कर सकते हैं। अगर कुछ नहीं हुआ तो क्या बात है? वे वास्तव में ये काम कर सकते हैं! लेकिन, वे हर बार एक नया स्ट्रिंग लौटाते हैं। लिखना व्यर्थ है
str1.replace("Java", "Python");
क्योंकि आप मूल वस्तु को नहीं बदल सकते। लेकिन, यदि आप विधि के परिणाम को एक नए संदर्भ चर में लिखते हैं, तो आप तुरंत अंतर देखेंगे!
public static void main(String[] args) {
String str1 = "I love Java";
String str2 = str1;// Both reference variables point to the same string.
System.out.println(str2);
String str1AfterReplacement = str1.replace("Java", "Python");
System.out.println(str2);
System.out.println(str1AfterReplacement);
}
सभी String
तरीके इसी तरह काम करते हैं। वस्तु का कुछ नहीं किया जा सकता "I love Java"
। आप केवल एक नई वस्तु बना सकते हैं और लिख सकते हैं: "<नई वस्तु> = हेरफेर का परिणाम। "I love Java" object "
अन्य कौन से प्रकार अपरिवर्तनीय हैं? कुछ जिन्हें आपको निश्चित रूप से तुरंत याद रखने की आवश्यकता होगी, आदिम प्रकारों के लिए सभी आवरण वर्ग हैं। Integer
, Byte
, Character
, Short
, Boolean
, Long
, Double
, Float
: ये सभी वर्ग immutable
ऑब्जेक्ट बनाते हैं (हम आगामी पाठों में उनके बारे में बात करेंगे)। इसमें बड़ी संख्या बनाने के लिए उपयोग की जाने वाली कक्षाएं शामिल हैं, जैसे कि BigInteger
और BigDecimal
। हमने हाल ही में अपवादों को कवर किया और स्टैक ट्रेस पर स्पर्श किया । खैर , अनुमान लगाओ, java.lang.StackTraceElementवस्तुएं भी अपरिवर्तनीय हैं। यह समझ में आता है: अगर कोई हमारे ढेर के डेटा को बदल सकता है, तो यह पूरी चीज को व्यर्थ कर देगा। कल्पना करें कि कोई व्यक्ति स्टैक ट्रेस से गुजर रहा है और OutOfMemoryError को FileNotFoundException में बदल रहा है । और फिर आप उस स्टैक का उपयोग त्रुटि का कारण खोजने के लिए करते हैं। लेकिन प्रोग्राम फाइलों का उपयोग भी नहीं करता है। :) तो, उन्होंने इन वस्तुओं को अपरिवर्तनीय बना दिया, बस मामले में। ठीक है, तो यह StackTraceElement के लिए कमोबेश समझ में आता है । लेकिन, स्ट्रिंग्स को अपरिवर्तनीय बनाने के लिए किसी को क्यों आवश्यकता होगी? उनके मूल्यों को बदलने में समस्या क्यों होगी? यह शायद और भी सुविधाजनक होगा। :/ इसके अनेक कारण हैं। सबसे पहले, यह स्मृति बचाता है। अपरिवर्तनीय तार को स्ट्रिंग पूल में रखा जा सकता है, स्ट्रिंग्स को नए बनाने के बजाय पुन: उपयोग करने की अनुमति देता है। दूसरा, सुरक्षा के लिए। उदाहरण के लिए, उपयोगकर्ता नाम और पासवर्ड लगभग हर प्रोग्राम में स्ट्रिंग्स होते हैं। उन्हें बदलने के लिए संभव बनाने से प्राधिकरण की समस्याएं हो सकती हैं। अन्य कारण भी हैं, लेकिन जावा के हमारे अध्ययन ने उन्हें अभी तक कवर नहीं किया है, इसलिए हम बाद में उन पर वापस आएंगे।
GO TO FULL VERSION