नमस्ते! आज हम एक महत्वपूर्ण तंत्र देखेंगे: नेस्टेड कक्षाओं में विरासत। क्या आपने कभी इस बारे में सोचा है कि यदि आपको एक नेस्टेड क्लास को किसी अन्य क्लास को इनहेरिट करने की आवश्यकता हो तो आप क्या करेंगे। यदि नहीं, तो मेरा विश्वास करो: यह स्थिति भ्रमित करने वाली हो सकती है, क्योंकि बहुत सारी बारीकियाँ हैं।
- क्या हम नेस्टेड क्लास को कुछ क्लास इनहेरिट कर रहे हैं? या क्या हम कुछ वर्ग को नेस्टेड क्लास का उत्तराधिकारी बना रहे हैं?
- क्या बच्चा/अभिभावक वर्ग सामान्य सार्वजनिक वर्ग है, या यह एक नेस्टेड वर्ग भी है?
- अंत में, इन सभी स्थितियों में हम किस प्रकार की नेस्टेड कक्षाओं का उपयोग करते हैं?
स्टेटिक नेस्टेड क्लासेस
उनके वंशानुक्रम नियम सबसे सरल हैं। यहां आप लगभग वह सब कुछ कर सकते हैं जो आपका दिल चाहता है। एक स्थिर नेस्टेड वर्ग इनहेरिट कर सकता है:- एक साधारण वर्ग
- एक स्थिर नेस्टेड वर्ग जिसे बाहरी वर्ग या उसके पूर्वजों में घोषित किया जाता है
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
आइए कोड को बदलने की कोशिश करें और एक Drawing
स्थिर नेस्टेड वर्ग और उसके वंशज - बनाएं Boeing737Drawing
।
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
जैसा कि आप देख सकते हैं, कोई समस्या नहीं है। हम वर्ग को बाहर भी निकाल सकते हैं Drawing
और इसे स्थिर नेस्टेड वर्ग के बजाय एक साधारण सार्वजनिक वर्ग बना सकते हैं - कुछ भी नहीं बदलेगा।
public class Drawing {
}
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Boeing737Drawing extends Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
हम इसे समझते हैं। लेकिन कौन सी कक्षाएं स्थिर नेस्टेड क्लास का उत्तराधिकारी हो सकती हैं? व्यावहारिक रूप से कोई भी! नेस्टेड/नॉन-नेस्टेड, स्टैटिक/नॉन-स्टैटिक - इससे कोई फर्क नहीं पड़ता। यहां हम Boeing737Drawing
इनर क्लास को Drawing
स्टैटिक नेस्टेड क्लास इनहेरिट करते हैं:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
public class Boeing737Drawing extends Drawing {
public int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
Boeing737Drawing
आप इस तरह का एक उदाहरण बना सकते हैं :
public class Main {
public static void main(String[] args) {
Boeing737 boeing737 = new Boeing737(1990);
Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
System.out.println(drawing.getMaxPassengersCount());
}
}
हालाँकि हमारी Boeing737Drawing
कक्षा को एक स्थिर वर्ग विरासत में मिला है, लेकिन यह स्वयं स्थिर नहीं है! नतीजतन, इसे हमेशा बाहरी वर्ग के उदाहरण की आवश्यकता होगी। हम Boeing737Drawing
क्लास को क्लास से हटा सकते हैं Boeing737
और इसे एक साधारण पब्लिक क्लास बना सकते हैं। कुछ नहीं बदलता है। यह अभी भी Drawing
स्टैटिक नेस्टेड क्लास को इनहेरिट कर सकता है।
public class Boeing737 {
private int manufactureYear;
public static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
}
}
public class Boeing737Drawing extends Boeing737.Drawing {
public int getMaxPassengersCount() {
return Boeing737.maxPassengersCount;
}
एकमात्र महत्वपूर्ण बिंदु यह है कि इस मामले में हमें स्थैतिक maxPassengersCount
चर को सार्वजनिक करने की आवश्यकता है। यदि यह निजी रहता है, तो एक साधारण सार्वजनिक वर्ग की उस तक पहुँच नहीं होगी। हमने स्थैतिक कक्षाओं का पता लगा लिया है! :) अब आंतरिक कक्षाओं की ओर बढ़ते हैं। वे 3 प्रकारों में आते हैं: साधारण आंतरिक वर्ग, स्थानीय वर्ग और अनाम आंतरिक वर्ग। फिर से, सरल से जटिल की ओर चलते हैं :)
अनाम आंतरिक वर्ग
एक अनाम आंतरिक वर्ग किसी अन्य वर्ग को इनहेरिट नहीं कर सकता है। कोई अन्य वर्ग अज्ञात वर्ग का उत्तराधिकारी नहीं हो सकता है। यह कोई आसान नहीं हो सकता! :)स्थानीय कक्षाएं
स्थानीय कक्षाएं (यदि आप भूल गए हैं) किसी अन्य वर्ग के कोड ब्लॉक के अंदर घोषित की जाती हैं। अधिकतर, यह बाहरी वर्ग की किसी विधि के अंदर होता है। तार्किक रूप से, एक ही विधि (या कोड ब्लॉक) के अंदर केवल अन्य स्थानीय वर्ग ही स्थानीय वर्ग को प्राप्त कर सकते हैं। यहाँ एक उदाहरण है:public class PhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber() {
this.phoneNumber = number;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
class CellPhoneNumber extends PhoneNumber {
}
class LandlinePhoneNumber extends PhoneNumber {
}
// ...number validation code
}
}
यह स्थानीय कक्षाओं पर हमारे पाठ का कोड है। हमारे संख्या सत्यापनकर्ता वर्ग में एक PhoneNumber
स्थानीय वर्ग है। यदि हमें इसकी आवश्यकता दो अलग-अलग संस्थाओं का प्रतिनिधित्व करने के लिए है, उदाहरण के लिए, एक मोबाइल फोन नंबर और एक लैंडलाइन फोन नंबर, तो हम इसे केवल एक ही तरीके से कर सकते हैं। कारण सरल है: स्थानीय वर्ग का दायरा उस विधि (कोड ब्लॉक) तक सीमित है जहां इसे घोषित किया गया है। नतीजतन, हम इसे बाहरी रूप से उपयोग नहीं कर पाएंगे (कक्षा विरासत सहित)। हालाँकि, स्थानीय वर्ग के भीतर विरासत की संभावनाएँ बहुत व्यापक हैं! एक स्थानीय वर्ग इनहेरिट कर सकता है:
- एक साधारण वर्ग।
- एक आंतरिक वर्ग जिसे उसी वर्ग में घोषित किया जाता है जिसे स्थानीय वर्ग या उसके पूर्वजों में से एक में घोषित किया जाता है।
- उसी विधि (कोड ब्लॉक) में घोषित एक अन्य स्थानीय वर्ग।
public class PhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
यहां हमने PhoneNumber
क्लास को मेथड से हटा दिया validatePhoneNumber()
और इसे लोकल क्लास के बजाय इनर क्लास बना दिया। यह हमें अपने 2 स्थानीय वर्गों को इनहेरिट करने से नहीं रोकता है। उदाहरण 2 — "... या इस वर्ग के पूर्वजों में।" अब यह और भी दिलचस्प है। हम PhoneNumber
इनहेरिटेंस चेन में और भी ऊपर जा सकते हैं। आइए एक सार वर्ग घोषित करें , जो हमारी कक्षा AbstractPhoneNumberValidator
का पूर्वज बन जाएगा :PhoneNumberValidator
public abstract class AbstractPhoneNumberValidator {
class PhoneNumber {
private String phoneNumber;
public PhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
}
जैसा कि आप देख सकते हैं, हमने इसे केवल घोषित नहीं किया - हमने PhoneNumber
इसमें आंतरिक वर्ग को भी स्थानांतरित कर दिया। हालाँकि, इसके वंशजों में PhoneNumberValidator
, विधियों में घोषित स्थानीय वर्ग PhoneNumber
बिना किसी समस्या के इनहेरिट कर सकते हैं!
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {
public void validatePhoneNumber(final String number) {
class CellPhoneNumber extends PhoneNumber {
public CellPhoneNumber(String phoneNumber) {
super(number);
}
}
class LandlinePhoneNumber extends PhoneNumber {
public LandlinePhoneNumber(String phoneNumber) {
super(number);
}
}
// ...number validation code
}
}
वंशानुक्रम संबंध के कारण, वंशज वर्ग के अंदर स्थानीय वर्ग पूर्वज के अंदर के आंतरिक वर्ग को "देख" सकते हैं। और अंत में, अंतिम समूह पर चलते हैं :)
भीतरी वर्ग
एक ही बाहरी वर्ग (या उसके वंशज) में घोषित एक आंतरिक वर्ग दूसरे आंतरिक वर्ग को प्राप्त कर सकता है। आइए आंतरिक कक्षाओं के पाठ से साइकिल के अपने उदाहरण का उपयोग करके इसका अन्वेषण करें।public class Bicycle {
private String model;
private int maxWeight;
public Bicycle(String model, int maxWeight) {
this.model = model;
this.maxWeight = maxWeight;
}
public void start() {
System.out.println("Let's go!");
}
class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
class SportSeat extends Seat {
// ...methods
}
}
यहां हमने क्लास Seat
के अंदर इनर क्लास को डिक्लेयर किया Bicycle
। एक विशेष प्रकार की रेसिंग सीट, SportSeat
इसे विरासत में मिली है। लेकिन, हम एक अलग "रेसिंग साइकिल" प्रकार बना सकते हैं और इसे एक अलग वर्ग में रख सकते हैं:
public class SportBicycle extends Bicycle {
public SportBicycle(String model, int maxWeight) {
super(model, maxWeight);
}
class SportSeat extends Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
यह भी एक विकल्प है। वंश का आंतरिक वर्ग ( SportBicycle.SportSeat
) पूर्वजों के आंतरिक वर्गों को "देखता है" और उन्हें विरासत में दे सकता है। आंतरिक कक्षाओं को इनहेरिट करने की एक बहुत ही महत्वपूर्ण विशेषता है! पिछले दो उदाहरणों में, हमारी SportSeat
कक्षा एक आंतरिक कक्षा थी। SportSeat
लेकिन क्या होगा अगर हम एक सामान्य सार्वजनिक वर्ग बनाने का फैसला करते हैं जो एक साथ Seat
आंतरिक वर्ग को विरासत में मिला है?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {
public SportSeat() {
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
हमें एक त्रुटि मिली! क्या आप अनुमान लगा सकते हैं क्यों? :) यह सब सीधा है। जब हमने Bicycle.Seat
आंतरिक वर्ग के बारे में बात की, तो हमने उल्लेख किया कि बाहरी वर्ग के एक उदाहरण का संदर्भ अंतर्निहित रूप से आंतरिक वर्ग के निर्माता को दिया जाता है। Seat
इसका अर्थ है कि आप बिना वस्तु बनाए वस्तु नहीं बना सकते Bicycle
। लेकिन ए के निर्माण के बारे में क्या SportSeat
? इसके विपरीत Seat
, इसमें बाहरी वर्ग के उदाहरण के संदर्भ में कन्स्ट्रक्टर को अंतर्निहित रूप से पारित करने के लिए यह अंतर्निहित तंत्र नहीं है। S जब तक, किसी Bicycle
वस्तु के बिना, हम किसी SportSeat
वस्तु का निर्माण नहीं कर सकते, जैसा कि के मामले में है Seat
। इसलिए, हमारे पास केवल एक चीज बची है - स्पष्ट रूप से कंस्ट्रक्टर को किसी वस्तु SportSeat
का संदर्भ देना । Bicycle
यह कैसे करना है:
class SportSeat extends Bicycle.Seat {
public SportSeat(Bicycle bicycle) {
bicycle.super();
}
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
हम नाउ का उपयोग करके सुपरक्लास कंस्ट्रक्टर को कॉल करते हैं super();
, अगर हम एक वस्तु बनाना चाहते हैं SportSeat
, तो हमें ऐसा करने से कोई नहीं रोकेगा:
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle("Peugeot", 120);
SportSeat peugeotSportSeat = new SportSeat(bicycle);
}
}
काहे! यह पाठ काफी लंबा था :) लेकिन आपने बहुत कुछ सीखा! अब कुछ कार्यों को हल करने का समय आ गया है! :)