जावा में स्टेटिक नेस्टेड क्लास, क्यों?


217

मैं जावा कोड को देख रहा था LinkedListऔर देखा कि यह एक स्थिर नेस्टेड क्लास का उपयोग करता है Entry

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

सामान्य आंतरिक वर्ग के बजाय एक स्थिर नेस्टेड वर्ग का उपयोग करने का कारण क्या है?

एकमात्र कारण जिसके बारे में मैं सोच सकता था, वह यह था कि एंट्री के पास इंस्टेंस वेरिएबल तक पहुंच नहीं है, इसलिए OOP के दृष्टिकोण से इसमें बेहतर एनकैप्सुलेशन है।

लेकिन मैंने सोचा कि प्रदर्शन के अन्य कारण भी हो सकते हैं। यह क्या हो सकता है?

ध्यान दें। मुझे आशा है कि मुझे मेरी शर्तें सही लगी हैं, मैंने इसे एक स्थिर आंतरिक वर्ग कहा होगा, लेकिन मुझे लगता है कि यह गलत है: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html


जवाबों:


271

आपके द्वारा लिंक किए गए सूर्य पृष्ठ में दोनों के बीच कुछ महत्वपूर्ण अंतर हैं:

एक नेस्टेड क्लास इसके संलग्न वर्ग का एक सदस्य है। गैर-स्थैतिक नेस्टेड कक्षाएं (आंतरिक कक्षाएं) को संलग्न वर्ग के अन्य सदस्यों तक पहुंच प्राप्त होती है, भले ही उन्हें निजी घोषित किया गया हो। स्टेटिक नेस्टेड क्लासेस के पास संलग्न वर्ग के अन्य सदस्यों तक पहुंच नहीं है।
...

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

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

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


बाह, मैं टिप्पणी करने के लिए काम करने के लिए एक लंगर लिंक प्राप्त करने के लिए प्रतीत नहीं कर सकते , लेकिन इसकी यह टिप्पणी:#comment113712_253507
Zach Lysobey

1
@matt b यदि किसी स्थिर नेस्टेड वर्ग के पास बाहरी वर्ग के उदाहरण सदस्यों तक पहुँच नहीं है, तो वह बाहरी वर्ग के उदाहरण सदस्यों के साथ कैसे बातचीत करता है?
गीक

1
@mattb लेकिन @Geek ने कैसे देखा, सूर्य पृष्ठ विरोधाभासी है: यह A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class कैसे संभव है अगर डॉक्स से पहले सिर्फ एक पैराग्राफ यह कहे कि: Static nested classes do not have access to other members of the enclosing class शायद वे कहना चाहेंगे: A nested (non-static) class interacts with the instance members of its outer class (and other classes) just like any other top-level class
tonix

1
@ डेविड लिंक के लिए धन्यवाद! हाँ, मैं गलत था, मेरी टिप्पणी को पढ़ते हुए अब मैं देखता हूं कि मेरा रीफ़्रेज़ गलत था। जैसा कि आपने कहा: An inner class interacts with the instance members through an implicit reference to its enclosing classऔर यह एक और दिलचस्प संपत्ति के non-static inner classesरूप में अच्छी तरह से anonymous inner classesया local classes defined inside a block: या उन सभी को इंगित करता है एक no-argनिर्माणकर्ता के पास कोई कारण नहीं हो सकता है संकलक संक्षेप में प्रत्येक रचनाकार के arg अनुक्रम को पूर्ववर्ती के एक उदाहरण के संदर्भ में पारित करने का आदेश देगा। कक्षा। बहुत साधारण।
टोनिक्स

1
आप बाहरी वर्ग को त्वरित करने के लिए स्थिर आंतरिक वर्ग का उपयोग कर सकते हैं जिसमें केवल निजी कंस्ट्रक्टर है। इसका उपयोग बिल्डर पैटर्न में किया जाता है। आप आंतरिक वर्ग के साथ ऐसा नहीं कर सकते।
सामीमुरुगन

47

मेरे दिमाग में, सवाल यह है कि जब भी आप एक आंतरिक वर्ग को देखते हैं, तो दूसरे तरीके का दौर होना चाहिए - क्या वास्तव में एक आंतरिक वर्ग होने की ज़रूरत है, अतिरिक्त जटिलता और निहित (स्पष्ट और स्पष्ट के बजाय, IMO) एक उदाहरण के संदर्भ में वर्ग युक्त?

माइंड यू, मैं एक C # फैन के रूप में पक्षपाती हूं - C # में आंतरिक वर्गों के बराबर नहीं है, हालांकि इसमें नेस्टेड प्रकार हैं। मैं यह नहीं कह सकता कि मैंने अभी तक आंतरिक कक्षाओं को याद किया है :)


4
मैं गलत हो सकता हूं, लेकिन यह मुझे एक स्थिर नेस्टेड क्लास के उदाहरण की तरह दिखता है, न कि एक आंतरिक वर्ग। वे यहां तक ​​कि उदाहरण में निर्दिष्ट करते हैं कि उनके पास नेस्टेड क्लास में आसपास के वर्ग पर उदाहरण चर तक पहुंच नहीं है।
कॉलिनडी

यूप, कोलिन का अधिकार - C # में आंतरिक वर्ग नहीं है, इसमें नेस्टेड कक्षाएं हैं। ध्यान रहे, C # में एक स्थिर नेस्टेड क्लास, जावा में एक स्थिर नेस्टेड क्लास के समान नहीं है :)
जॉन स्कीट

2
नेस्टेड प्रकार उन क्षेत्रों में से एक हैं जहां सी # को जावा की तुलना में यह बहुत सही लगा। मैं हमेशा इसकी अर्थपूर्ण / तार्किक शुद्धता पर ध्यान देता हूं ..
nawfal

3
@nffal: हां, कुछ निशानों को छोड़कर मैं इस बात से आश्चर्य में हूं कि C # भाषा को कितनी अच्छी तरह डिजाइन (और निर्दिष्ट) किया गया है।
जॉन स्कीट

1
@JonSkeet क्या आपके पास एक लेख या ब्लॉग है जो उन निगल्स हैं? मुझे लगता है कि आप "निगल्स" के रूप में जो कुछ भी चाहते हैं, उसके साथ जाना पसंद करेंगे :)
nawfal

27

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


यदि 'बाहरी' वर्ग अंतिम है और इसलिए इसे तुरंत लागू नहीं किया जा सकता है, तो क्या यह तर्क उस मामले में समझ में आता है? क्योंकि किसी बाहरी वर्ग का संदर्भ रखना / रखना बेकार है, यदि बाद वाला अंतिम है।
10ad में 10

10

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

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


8

बिल्डर पैटर्न में स्टेटिक इनर क्लास का उपयोग किया जाता है। स्टेटिक इनर क्लास यह बाहरी वर्ग को तुरंत बदल सकता है जिसमें केवल निजी कंस्ट्रक्टर है। तो आप बाहरी वर्ग को तुरंत चलाने के लिए स्थिर आंतरिक वर्ग का उपयोग कर सकते हैं जिसमें केवल निजी कंस्ट्रक्टर है। आप आंतरिक वर्ग के साथ वैसा नहीं कर सकते जैसा कि आपको आंतरिक वर्ग तक पहुंचने से पहले बनाई गई बाहरी कक्षा की वस्तु की आवश्यकता होती है।

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

यह x: 1 आउटपुट करेगा


7

स्थिर नेस्टेड क्लास किसी भी अन्य बाहरी वर्ग की तरह है, क्योंकि इसमें बाहरी वर्ग के सदस्यों की पहुंच नहीं है।

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

इस तरह के उपयोग के लिए उदाहरण, आप Android R.java (संसाधनों) फ़ाइल में पा सकते हैं। एंड्रॉइड के Res फ़ोल्डर में लेआउट्स (स्क्रीन डिज़ाइन वाले), ड्रॉएबल फोल्डर (प्रोजेक्ट के लिए उपयोग की जाने वाली छवियां), मान फ़ोल्डर (जिसमें स्ट्रिंग स्थिरांक होते हैं) आदि शामिल हैं।

साइन सभी फ़ोल्डर Res फ़ोल्डर का हिस्सा हैं, Android उपकरण एक R.java (संसाधन) फ़ाइल उत्पन्न करता है जिसमें आंतरिक रूप से उनके प्रत्येक आंतरिक फ़ोल्डर के लिए बहुत से स्थिर नेस्टेड वर्ग होते हैं।

यहाँ Android में उत्पन्न R.java फाइल का लुक और फील है: यहाँ वे केवल पैकेजिंग सुविधा के लिए उपयोग कर रहे हैं।

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}

6

से http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html :

यदि आपको किसी एन्कोडिंग इंस्टेंस के गैर-सार्वजनिक फ़ील्ड और विधियों तक पहुँच की आवश्यकता हो तो एक गैर-स्थिर नेस्टेड क्लास (या इनर क्लास) का उपयोग करें। यदि आपको इस पहुँच की आवश्यकता नहीं है, तो एक स्थिर नेस्टेड क्लास का उपयोग करें।


4

सरल उदाहरण:

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

यदि गैर-स्थैतिक वर्ग को उच्च वर्ग के उदाहरण में तुरंत समाप्त नहीं किया जा सकता है (तो उदाहरण में नहीं जहां मुख्य एक स्थिर फ़ंक्शन है)


आपका StaticInnerClass वास्तव में, एक स्थिर नेस्टेड / आंतरिक वर्ग नहीं है। यह एक शीर्ष स्तर का स्थिर वर्ग है।
theRiley

2

स्थैतिक बनाम सामान्य कारणों में से एक को क्लास लोडिंग के साथ करना पड़ता है। आप इसके माता-पिता के निर्माण में एक आंतरिक वर्ग को तुरंत नहीं कर सकते।

पुनश्च: मैंने हमेशा 'नेस्टेड' और 'इनर' को इंटरचेंज करने योग्य समझा है। शर्तों में सूक्ष्म बारीकियां हो सकती हैं, लेकिन अधिकांश जावा डेवलपर्स या तो समझेंगे।


1

नॉन स्टैटिक इनर क्लास का परिणाम मेमोरी लीक्स में हो सकता है जबकि स्टैटिक इनर क्लास उनके खिलाफ प्रोटेक्ट करेगा। यदि बाहरी वर्ग काफी डेटा रखता है, तो यह एप्लिकेशन के प्रदर्शन को कम कर सकता है।


'स्टैटिक इनर' शब्दों में एक विरोधाभास है।
लोर्ने

1
@ ईजेपी, शीश ... लोग वास्तव में किसी भी समय यह इंगित करके बंद कर देते हैं कि कोई व्यक्ति "स्थिर आंतरिक वर्गों" का उल्लेख करता है ...
साकिबॉय

0

मुझे प्रदर्शन अंतर के बारे में पता नहीं है, लेकिन जैसा कि आप कहते हैं, स्टेटिक नेस्टेड क्लास एनक्लोजिंग क्लास के उदाहरण का हिस्सा नहीं है। एक स्थिर नेस्टेड क्लास बनाने के लिए बस सरल लगता है जब तक कि आपको वास्तव में आंतरिक वर्ग होने की आवश्यकता न हो।

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


एक मासूम वर्ग 'एन्क्लोज़िंग क्लास के उदाहरण का हिस्सा नहीं है'।
लोर्ने

एक आंतरिक वर्ग अस्तित्वगत रूप से संलग्न वर्ग पर निर्भर है, और संलग्न वर्ग के सदस्यों के लिए अंतरंग पहुंच है, इसलिए यह वास्तव में संलग्न वर्ग का एक हिस्सा है। वास्तव में, यह एक सदस्य है।
रिले

0

गैर-स्थिर के बजाय एक स्थिर नेस्टेड क्लास का उपयोग करना कुछ मामलों में रिक्त स्थान को बचा सकता है। उदाहरण के लिए: Comparatorकिसी कक्षा के अंदर, छात्र का कहना है।

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

फिर static सुनिश्चित करता है कि छात्र वर्ग के पास केवल एक तुलनाकर्ता है, बजाय एक नए के हर बार एक नया छात्र उदाहरण बनाने के लिए।


-1

आंतरिक वर्ग का प्रवेश

  1. एक समय का उपयोग करें
  2. समर्थन और encapsulation में सुधार
  3. readibility
  4. निजी क्षेत्र की पहुंच

बाहरी वर्ग के मौजूदा के बिना आंतरिक वर्ग मौजूद नहीं होगा।

class car{
    class wheel{

    }
}

आंतरिक वर्ग चार प्रकार के होते हैं।

  1. सामान्य आंतरिक वर्ग
  2. विधि स्थानीय आंतरिक वर्ग
  3. अनाम आंतरिक वर्ग
  4. स्थिर आंतरिक वर्ग

बिंदु ---

  1. स्थिर आंतरिक वर्ग से, हम केवल बाहरी वर्ग के स्थिर सदस्य तक ही पहुँच सकते हैं।
  2. आंतरिक वर्ग के अंदर हम स्थिर सदस्य की घोषणा नहीं कर सकते।
  3. बाहरी वर्ग के स्थिर क्षेत्र में सामान्य आंतरिक वर्ग को आह्वान करने के लिए इनवर्टर।

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  4. बाहरी वर्ग के उदाहरण क्षेत्र में सामान्य आंतरिक वर्ग को लागू करने के लिए इनवर्टर।

    Inner i=new Inner();

  5. बाहरी कक्षा के बाहर सामान्य आंतरिक वर्ग को लागू करने के लिए इनवर्टर।

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  6. इनर क्लास के अंदर यह पॉइंटर इनर क्लास के अंदर होता है।

    this.member-current inner class outerclassname.this--outer class

  7. आंतरिक श्रेणी लागू संशोधक के लिए है - सार्वजनिक, डिफ़ॉल्ट,

    final,abstract,strictfp,+private,protected,static

  8. आउटर $ इनर आंतरिक वर्ग का नाम है।

  9. उदाहरण विधि के अंदर आंतरिक वर्ग तो हम स्थैतिक और बाहरी वर्ग के उदाहरण क्षेत्र को प्राप्त कर सकते हैं।

स्थैतिक विधि के अंदर 10.inner वर्ग तो हम केवल स्थैतिक क्षेत्र का उपयोग कर सकते हैं

बाहरी वर्ग।

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.