खोज…


परिचय

जावा का उपयोग करके, डेवलपर्स के पास एक वर्ग को दूसरे वर्ग के भीतर परिभाषित करने की क्षमता है। ऐसे वर्ग को नेस्टेड क्लास कहा जाता है। नेस्टेड क्लासेस को इनर क्लासेस कहा जाता है यदि उन्हें गैर-स्टेटिक घोषित किया गया था, यदि नहीं, तो उन्हें बस स्टैटिक नेस्टेड क्लासेस कहा जाता है। यह पृष्ठ जावा नेस्टेड और इनर क्लासेस का उपयोग करने के बारे में उदाहरणों के साथ विवरण प्रदान करता है।

वाक्य - विन्यास

  • सार्वजनिक वर्ग OuterClass {सार्वजनिक वर्ग InnerClass {}} // आंतरिक वर्ग भी निजी हो सकते हैं
  • सार्वजनिक वर्ग OuterClass {सार्वजनिक स्थैतिक वर्ग StaticNestedClass {}} // स्टेटिक नेस्टेड वर्ग भी निजी हो सकते हैं
  • सार्वजनिक शून्य विधि () {निजी वर्ग LocalClass {}} // स्थानीय वर्ग हमेशा निजी होते हैं
  • SomeClass गुमनामClassInstance = नया SomeClass () {}; // बेनामी आंतरिक वर्गों का नाम नहीं दिया जा सकता है, इसलिए पहुंच मूट है। यदि 'SomeClass ()' सार है, तो शरीर को सभी अमूर्त विधियों को लागू करना चाहिए।
  • SomeInterface अनामClassInstance = नया SomeInterface () {}; // शरीर को सभी इंटरफ़ेस विधियों को लागू करना चाहिए।

टिप्पणियों

शब्दावली और वर्गीकरण

जावा लैंग्वेज स्पेसिफिकेशन (JLS) विभिन्न प्रकार के जावा क्लास को निम्नानुसार वर्गीकृत करता है:

एक शीर्ष स्तर वर्ग एक ऐसा वर्ग है जो एक नेस्टेड वर्ग नहीं है।

एक नेस्टेड क्लास कोई भी वर्ग होता है जिसकी घोषणा दूसरे वर्ग या इंटरफ़ेस के निकाय के भीतर होती है।

एक आंतरिक वर्ग एक नेस्टेड वर्ग है जो स्पष्ट रूप से या अंतर्निहित रूप से स्थिर घोषित नहीं किया गया है।

एक आंतरिक वर्ग एक गैर-स्थैतिक सदस्य वर्ग , एक स्थानीय वर्ग या एक अनाम वर्ग हो सकता है । एक इंटरफ़ेस का एक सदस्य वर्ग अंतर्निहित रूप से स्थिर है इसलिए इसे कभी भी आंतरिक वर्ग नहीं माना जाता है।

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

ध्यान दें कि अनाम आंतरिक कक्षाओं और लैम्ब्डा के बीच एक करीबी रिश्ता है, लेकिन लैम्ब्डा कक्षाएं हैं।

शब्दार्थ भेद

  • शीर्ष स्तर की कक्षाएं "बेस केस" हैं। वे पहुँच संशोधक शब्दार्थ के आधार पर सामान्य दृश्यता नियमों के अधीन एक कार्यक्रम के अन्य भागों में दिखाई देते हैं। यदि गैर-अमूर्त हैं, तो उन्हें किसी भी कोड द्वारा त्वरित किया जा सकता है, जहां एक्सेस मॉडिफायर के आधार पर संबंधित कंस्ट्रक्टर दिखाई देते हैं।

  • स्टैटिक नेस्टेड क्लास दो अपवादों के साथ शीर्ष स्तर की कक्षाओं के समान पहुंच और तात्कालिकता नियमों का पालन करते हैं:

    • एक नेस्टेड वर्ग को private घोषित किया जा सकता है, जो इसे अपने शीर्ष स्तरीय वर्ग के बाहर दुर्गम बनाता है।
    • एक नेस्टेड वर्ग के पास शीर्ष स्तर के वर्ग और उसके सभी परीक्षित वर्ग के private सदस्यों तक पहुंच है।

    यह स्थिर नेस्टेड वर्गों को उपयोगी बनाता है जब आपको एक तंग अमूर्त सीमा के भीतर कई "इकाई प्रकार" का प्रतिनिधित्व करने की आवश्यकता होती है; उदाहरण के लिए जब नेस्टेड कक्षाओं का उपयोग "कार्यान्वयन विवरण" को छिपाने के लिए किया जाता है।

  • इनर क्लासेस गैर-स्थिर वैरिएबल को एक्सेस करने की क्षमता जोड़ते हैं जो एन्कोडिंग स्कोप में घोषित किए गए हैं:

    • एक गैर-स्थैतिक सदस्य वर्ग उदाहरण चर का उल्लेख कर सकता है।
    • एक स्थानीय वर्ग (एक विधि के भीतर घोषित) विधि के स्थानीय चर को भी संदर्भित कर सकता है, बशर्ते कि वे final । (जावा 8 और बाद के लिए, वे प्रभावी रूप से अंतिम हो सकते हैं।)
    • एक अनाम आंतरिक वर्ग को एक वर्ग या एक विधि के भीतर घोषित किया जा सकता है, और समान नियमों के अनुसार चर का उपयोग कर सकते हैं।

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

नेस्टेड क्लास का उपयोग करते हुए एक साधारण स्टैक

public class IntStack {

    private IntStackNode head;

    // IntStackNode is the inner class of the class IntStack
    // Each instance of this inner class functions as one link in the
    // Overall stack that it helps to represent
    private static class IntStackNode {

        private int val;
        private IntStackNode next;

        private IntStackNode(int v, IntStackNode n) {
            val = v;
            next = n;
        }
    }

    public IntStack push(int v) {
        head = new IntStackNode(v, head);
        return this;
    }

    public int pop() {
        int x = head.val;
        head = head.next;
        return x;
    }
}

और इसके उपयोग, जो (विशेष रूप से) नेस्टेड क्लास के अस्तित्व को स्वीकार नहीं करता है।

public class Main {
    public static void main(String[] args) {
 
        IntStack s = new IntStack();
        s.push(4).push(3).push(2).push(1).push(0);

        //prints: 0, 1, 2, 3, 4, 
        for(int i = 0; i < 5; i++) {
            System.out.print(s.pop() + ", ");
        }            
    }
}

स्टेटिक बनाम नॉन स्टेटिक नेस्टेड क्लासेस

नेस्टेड क्लास बनाते समय, आपके पास उस नेस्टेड क्लास स्टैटिक होने का एक विकल्प होता है:

public class OuterClass1 {

    private static class StaticNestedClass {

    }

}

या गैर-स्थिर:

public class OuterClass2 {

    private class NestedClass {

    }

}

इसके मूल में, स्थिर नीडिंत वर्ग के पास बाहरी वर्ग का कोई आसन्न उदाहरण नहीं होता है , जबकि गैर-स्थिर नेस्टेड वर्ग करते हैं। यह दोनों को प्रभावित करता है जहां / जब किसी को नेस्टेड क्लास को तत्काल करने की अनुमति दी जाती है, और उन नेस्टेड वर्गों के कौन से उदाहरणों को एक्सेस करने की अनुमति दी जाती है। उपरोक्त उदाहरण में जोड़ना:

public class OuterClass1 {

    private int aField;
    public void aMethod(){}

    private static class StaticNestedClass {
        private int innerField;

        private StaticNestedClass() {
             innerField = aField; //Illegal, can't access aField from static context 
             aMethod();           //Illegal, can't call aMethod from static context 
        }

        private StaticNestedClass(OuterClass1 instance) {
             innerField = instance.aField; //Legal
        }

    }

    public static void aStaticMethod() {
        StaticNestedClass s = new StaticNestedClass(); //Legal, able to construct in static context
        //Do stuff involving s...
    }

}

public class OuterClass2 {

    private int aField;

    public void aMethod() {}

    private class NestedClass {
        private int innerField;

        private NestedClass() {
             innerField = aField; //Legal   
             aMethod(); //Legal
        }
    }

    public void aNonStaticMethod() {
        NestedClass s = new NestedClass(); //Legal
    }

    public static void aStaticMethod() {
        NestedClass s = new NestedClass(); //Illegal. Can't construct without surrounding OuterClass2 instance.
                                         //As this is a static context, there is no surrounding OuterClass2 instance
    }
}

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

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

इनर क्लासेस के लिए एक्सेस मॉडिफायर

जावा में एक्सेस मॉडिफायर का पूरा विवरण यहां पाया जा सकता है । लेकिन वे आंतरिक कक्षाओं के साथ कैसे बातचीत करते हैं?

public , हमेशा की तरह, किसी भी दायरे में अप्रतिबंधित पहुँच को एक्सेस करने में सक्षम बनाता है।

public class OuterClass {

    public class InnerClass {

        public int x = 5;

    }

    public InnerClass createInner() {
        return new InnerClass();
    }
}

public class SomeOtherClass {

    public static void main(String[] args) {
        int x = new OuterClass().createInner().x; //Direct field access is legal
    }
}

दोनों protected और डिफ़ॉल्ट संशोधक (कुछ भी नहीं) अपेक्षा के अनुरूप व्यवहार करते हैं, वे भी गैर-नेस्टेड वर्गों के लिए करते हैं।

private , दिलचस्प रूप से पर्याप्त, उस वर्ग के लिए प्रतिबंधित नहीं करता है जिसका वह संबंध है। बल्कि, यह संकलन इकाई - .java फ़ाइल के लिए प्रतिबंधित है। इसका मतलब यह है कि बाहरी वर्गों के पास इनर क्लास फील्ड्स और तरीकों तक पूरी पहुंच है, भले ही वे private रूप से चिह्नित हों।

public class OuterClass {

    public class InnerClass {

        private int x;
        private void anInnerMethod() {}
    }

    public InnerClass aMethod() {
        InnerClass a = new InnerClass();
        a.x = 5; //Legal
        a.anInnerMethod(); //Legal
        return a;
    }
}

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

public class OuterClass {

    private class InnerClass{}

    public InnerClass makeInnerClass() {
        return new InnerClass();
    }
}

public class AnotherClass {

    public static void main(String[] args) {
        OuterClass o = new OuterClass();
     
        InnerClass x = o.makeInnerClass(); //Illegal, can't find type
        OuterClass.InnerClass x = o.makeInnerClass(); //Illegal, InnerClass has visibility private
        Object x = o.makeInnerClass(); //Legal
    }
}

अनाम आंतरिक कक्षाएं

एक अनाम आंतरिक वर्ग आंतरिक वर्ग का एक रूप है जो एक ही कथन के साथ घोषित और त्वरित होता है। परिणामस्वरूप, उस वर्ग का कोई नाम नहीं है जिसका उपयोग कार्यक्रम में कहीं और किया जा सकता है; यानी यह गुमनाम है।

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

public static Comparator<String> CASE_INSENSITIVE =
        new Comparator<String>() {
            @Override
            public int compare(String string1, String string2) {
                return string1.toUpperCase().compareTo(string2.toUpperCase());
            }
        };

यह अनाम वर्ग एक Comparator<String> ऑब्जेक्ट ( CASE_INSENSITIVE ) को परिभाषित करता है जो मामले में अंतर की अनदेखी करने वाले दो तारों की तुलना करता है।

अन्य इंटरफेस जो अक्सर कार्यान्वित किए जाते हैं और अनाम कक्षाओं का उपयोग करके Runnable होते हैं, वे Runnable और Callable । उदाहरण के लिए:

// An anonymous Runnable class is used to provide an instance that the Thread
// will run when started.
Thread t = new Thread(new Runnable() {
        @Override 
        public void run() {
              System.out.println("Hello world");
        }
    });
t.start();  // Prints "Hello world"

अनाम आंतरिक कक्षाएं भी कक्षाओं पर आधारित हो सकती हैं। इस मामले में, अनाम वर्ग निहित रूप से मौजूदा वर्ग का extends करता है। यदि विस्तारित किया जा रहा वर्ग सार है, तो अनाम वर्ग को सभी सार विधियों को लागू करना होगा। यह गैर-अमूर्त तरीकों को भी ओवरराइड कर सकता है।

कंस्ट्रक्टर्स

एक अनाम वर्ग में एक स्पष्ट निर्माता नहीं हो सकता है। इसके बजाय, एक निहित कंस्ट्रक्टर को परिभाषित किया जाता है जो क्लास में एक कंस्ट्रक्टर को किसी भी पैरामीटर को पास करने के लिए super(...) का उपयोग करता है। उदाहरण के लिए:

SomeClass anon = new SomeClass(1, "happiness") {
            @Override
            public int someMethod(int arg) {
                // do something
            }
        };

के बारे में हमारी गुमनाम उपवर्ग के लिए अंतर्निहित निर्माता SomeClass के एक निर्माता फोन करेगा SomeClass है कि कॉल हस्ताक्षर से मेल खाता है SomeClass(int, String) । यदि कोई कंस्ट्रक्टर उपलब्ध नहीं है, तो आपको एक संकलन त्रुटि मिलेगी। मिलान किए गए कंस्ट्रक्टर द्वारा फेंके गए किसी भी अपवाद को निहित कंस्ट्रक्टर द्वारा भी फेंक दिया जाता है।

स्वाभाविक रूप से, यह एक इंटरफ़ेस का विस्तार करते समय काम नहीं करता है। जब आप एक इंटरफ़ेस से एक अनाम वर्ग बनाते हैं, तो कक्षाएं सुपरक्लास java.lang.Object होती java.lang.Object जिसमें केवल एक नो-आर्ग्स कंस्ट्रक्टर होता है।

विधि स्थानीय आंतरिक कक्षाएं

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

एक विधि-स्थानीय आंतरिक वर्ग केवल उस पद्धति के भीतर त्वरित किया जा सकता है जहां आंतरिक वर्ग परिभाषित किया गया है।

विधि का उपयोग करने का उदाहरण स्थानीय आंतरिक वर्ग:

public class OuterClass {
    private void outerMethod() {
       final int outerInt = 1;
        // Method Local Inner Class
        class MethodLocalInnerClass {
            private void print() {
                System.out.println("Method local inner class " + outerInt);
            }
        }
        // Accessing the inner class
        MethodLocalInnerClass inner = new MethodLocalInnerClass();
        inner.print();
    }

    public static void main(String args[]) {
        OuterClass outer = new OuterClass();
        outer.outerMethod();
    }
}

निष्पादन एक आउटपुट देगा: Method local inner class 1

एक गैर-स्थिर आंतरिक वर्ग से बाहरी वर्ग तक पहुंच

बाहरी वर्ग का संदर्भ वर्ग के नाम और this का उपयोग करता है

public class OuterClass {
    public class InnerClass {
        public void method() {
            System.out.println("I can access my enclosing class: " + OuterClass.this);
        }
    }
}

आप बाहरी वर्ग के क्षेत्रों और विधियों को सीधे एक्सेस कर सकते हैं।

public class OuterClass {
    private int counter;

    public class InnerClass {
        public void method() {
            System.out.println("I can access " + counter);
        }
    }
}

लेकिन नाम टक्कर के मामले में आप बाहरी वर्ग के संदर्भ का उपयोग कर सकते हैं।

public class OuterClass {
    private int counter;

    public class InnerClass {
        private int counter;
        
        public void method() {
            System.out.println("My counter: " + counter);
            System.out.println("Outer counter: " + OuterClass.this.counter);
            
            // updating my counter
            counter = OuterClass.this.counter;
        }
    }
}

बाहर से गैर-स्थिर आंतरिक वर्ग का उदाहरण बनाएं

एक आंतरिक वर्ग जो किसी भी बाहरी वर्ग को दिखाई देता है, उसे इस वर्ग से भी बनाया जा सकता है।

भीतर का वर्ग बाहरी वर्ग पर निर्भर करता है और इसके उदाहरण के लिए संदर्भ की आवश्यकता होती है। आंतरिक वर्ग का एक उदाहरण बनाने के लिए, new ऑपरेटर को केवल बाहरी वर्ग के उदाहरण पर कॉल करने की आवश्यकता होती है।

class OuterClass {

    class InnerClass {
    }
}

class OutsideClass {

    OuterClass outer = new OuterClass();
    
    OuterClass.InnerClass createInner() {
        return outer.new InnerClass();
    }
}

outer.new रूप में उपयोग पर ध्यान दें। outer.new



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow