जावा आंतरिक वर्गों में स्थिर क्षेत्रों को क्यों प्रतिबंधित करता है?


85
class OuterClass {
 class InnerClass {
  static int i = 100; // compile error
  static void f() { } // compile error
 }
} 

हालाँकि इसके साथ स्थिर क्षेत्र तक OuterClass.InnerClass.iपहुँचना संभव नहीं है , अगर मैं कुछ ऐसा रिकॉर्ड करना चाहता हूँ जो स्थिर होना चाहिए, जैसे बनाए गए इनरक्लास ऑब्जेक्ट्स की संख्या, तो उस फ़ील्ड को स्थिर बनाने में मदद मिलेगी। तो जावा आंतरिक कक्षाओं में स्थैतिक क्षेत्रों / विधियों पर प्रतिबंध क्यों लगाता है?

संपादित करें: मैं जानता हूँ कि संकलक को नेस्टेड नेस्टेड क्लास (या स्टैटिक इनर क्लास) से कैसे खुश किया जा सकता है, लेकिन जो मैं जानना चाहता हूँ, वह यह है कि जावा स्टैब्लिक फील्ड / इनर क्लास (या साधारण इनर क्लास) के अंदर दोनों भाषा डिज़ाइन से मना करता है और कार्यान्वयन पहलुओं, अगर कोई इसके बारे में अधिक जानता है।


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

जवाबों:


32

आंतरिक कक्षाओं के पीछे का विचार संलग्न उदाहरण के संदर्भ में काम करना है। किसी तरह, स्थैतिक चर और तरीकों की अनुमति इस प्रेरणा का खंडन करती है?

8.1.2 आंतरिक कक्षाएं और संलग्नक उदाहरण

एक आंतरिक वर्ग एक नेस्टेड वर्ग है जो स्पष्ट रूप से या स्पष्ट रूप से स्थिर घोषित नहीं किया जाता है। हो सकता है कि आंतरिक वर्ग स्थिर इनिशियलाइज़र ()8.7) या सदस्य इंटरफेस की घोषणा न करें। जब तक वे संकलन-समय स्थिर फ़ील्ड (are15.28) नहीं होते हैं, तब तक आंतरिक वर्ग स्थिर सदस्यों की घोषणा नहीं कर सकते।


18
शायद यह सिर्फ इस तरह तय किया गया है
ग्रेगरी पकोस

3
आप माता-पिता के संदर्भ के बिना गैर-स्थिर आंतरिक को तुरंत नहीं कर सकते , लेकिन आप अभी भी इसे इनिशियलाइज़ कर सकते हैं ।
स्कैफ़मैन

अगर क्लास-प्लेयर्स एक कैश रखते हैं जो कहता है कि "क्लास एक्स को इनिशियलाइज़ किया गया है", तो उनके तर्क का इस्तेमाल क्लास के कई इंस्टेंस [ऑब्जेक्ट्स रिप्रेजेंट] एक्स के इनिशियलाइज़ेशन के लिए नहीं किया जा सकता (जो कि तब ज़रूरी होता है जब क्लास ऑब्जेक्ट्स को कई के अंदर इनर क्लास के रूप में इंस्टैंट किया जाना चाहिए) अलग वस्तुएं)।
इरविन स्मौट

@skaffman यह अभी भी समझ में नहीं आता है। आंतरिक वर्ग के स्थैतिक गुणों को केवल एक बार आरंभ किया जाएगा, तो समस्या क्या होगी? अभी, मेरे पास एक स्थिर हैशमैप है और मेरे पास लगभग 4 विधियां हैं जो केवल इस नक्शे में हेरफेर करती हैं, जिससे एक आंतरिक कक्षा में सब कुछ समूह के लिए और अधिक आदर्श हो जाता है। हालाँकि, स्टैटिक हैशमैप को अब बाहर रहना होगा, और संभवतः संबंधित अन्य चीजें, जो सिर्फ सादा बेवकूफ हैं। स्थैतिक गुणों को शुरू करने के साथ समस्या क्या होगी?
mmm

54

मैं यह जानना चाहता हूं कि जावा स्टैबल फील्ड्स / मेथड्स को अंदर की कक्षाओं के लिए मना क्यों करता है

क्योंकि वे आंतरिक वर्ग "उदाहरण" हैं जो आंतरिक कक्षाएं हैं। यही है, वे संलग्न वस्तु के एक उदाहरण विशेषता की तरह हैं।

चूंकि वे "उदाहरण" वर्ग हैं, इसलिए staticसुविधाओं को अनुमति देने का कोई मतलब नहीं है, क्योंकि staticपहली जगह में उदाहरण के बिना काम करना है।

यह ऐसा है जैसे आप एक ही समय में एक स्थिर / इंस्टेंस विशेषता बनाने की कोशिश करते हैं।

निम्नलिखित उदाहरण लें:

class Employee {
    public String name;
}

यदि आप कर्मचारी के दो उदाहरण बनाते हैं:

Employee a = new Employee(); 
a.name = "Oscar";

Employee b = new Employee();
b.name = "jcyang";

यह स्पष्ट है कि संपत्ति के लिए प्रत्येक का अपना मूल्य क्यों है name, है ना?

भीतर के वर्ग के साथ भी ऐसा ही होता है; प्रत्येक आंतरिक वर्ग उदाहरण अन्य आंतरिक वर्ग उदाहरण से स्वतंत्र है।

इसलिए यदि आप एक counterवर्ग विशेषता बनाने का प्रयास करते हैं , तो उस मूल्य को दो अलग-अलग उदाहरणों में साझा करने का कोई तरीका नहीं है।

class Employee {
    public String name;
    class InnerData {
        static count; // ??? count of which ? a or b? 
     }
}

जब आप उदाहरण aऔर bउपरोक्त उदाहरण बनाते हैं , तो स्थिर चर के लिए एक सही मूल्य क्या होगा count? इसे निर्धारित करना संभव नहीं है, क्योंकि InnerDataकक्षा का अस्तित्व पूरी तरह से प्रत्येक संलग्न वस्तुओं पर निर्भर करता है।

इसीलिए, जब वर्ग के रूप में घोषित किया जाता है static, तो उसे खुद को जीने के लिए एक जीवित उदाहरण की आवश्यकता नहीं होती है। अब जब कोई निर्भरता नहीं है, तो आप स्वतंत्र रूप से एक स्थिर विशेषता की घोषणा कर सकते हैं।

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


4
मैं आपके स्पष्टीकरण को आंतरिक वर्ग के स्थिर गुणों के लिए खरीदूंगा, लेकिन जैसा कि @skaffman मेरे जवाब में एक टिप्पणी में बताता है, स्थैतिक तरीकों के बारे में क्या ? ऐसा लगता है जैसे कि तरीकों को अनुमति दिए बिना अनुमति दी जानी चाहिए कि उन्हें किसी भी उदाहरण से अलग किया जाए। वास्तव में, जावा में, आप इंस्टेंस पर स्थिर तरीकों को कॉल कर सकते हैं (हालांकि इसे खराब शैली माना जाता है)। BTW: मैंने एक सहयोगी से ओपी कोड को C # के रूप में संकलित करने का प्रयास करने के लिए कहा और यह संकलन करता है । तो C # जाहिरा तौर पर यह अनुमति देता है जो दर्शाता है कि ओपी जो करना चाहता है वह कुछ मौलिक ओओ सिद्धांत का उल्लंघन नहीं करता है।
असफ

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

1
C # के बारे में ... अच्छी तरह से। यह OO केवल इसलिए मान्य नहीं है क्योंकि C # इसकी अनुमति देता है, मेरा मतलब यह नहीं है कि यह गलत है, लेकिन C # में निरंतरता की कीमत पर भी विकास को आसान बनाने के लिए कई प्रतिमान शामिल हैं (आपको प्रत्येक .NET रिलीज के साथ नई चीजें सीखना होगा) और यह दूसरों के बीच इस और अन्य प्रकार की चीजों की अनुमति देता है। मुझे लगता है कि यह अच्छी बात है। यदि समुदाय को लगता है कि एक अतिरिक्त सुविधा पर्याप्त शांत है तो C # भविष्य में हो सकता है।
OscarRyz

2
@OscarRyz आपको अपने स्थिर तरीकों / क्षेत्रों का उपयोग करने के लिए आंतरिक वर्ग के उदाहरणों की आवश्यकता क्यों है ? और [उपयोगी] भीतरी कक्षा में स्थिर विधि का एक उदाहरण है निजी सहायक विधि।
लियोनिद शिमोनोनोव

1
उपयोग के साथ final, जावा में आंतरिक वर्ग में स्थिर क्षेत्रों की अनुमति है। आप इस परिदृश्य की व्याख्या कैसे करते हैं?
नंबर 945

34

InnerClassstaticसदस्य नहीं हो सकते क्योंकि यह एक उदाहरण ( OuterClass) का है। आप यह घोषणा करते हैं InnerClassके रूप में staticउदाहरण से अलग कर, अपने कोड संकलित कर देगा।

class OuterClass {
    static class InnerClass {
        static int i = 100; // no compile error
        static void f() { } // no compile error
    }
}

BTW: आप अभी भी के उदाहरण बनाने में सक्षम हो जाएगा InnerClassstaticइस संदर्भ में अनुमति देता है कि एक उदाहरण के बिना संलग्न होने के लिए OuterClass


6
InnerClassइसका संबंध नहीं है OuterClass, इसके उदाहरण हैं। खुद दो वर्गों का इस तरह का कोई संबंध नहीं है। क्यों आप InnerClassअभी भी खड़ा है में स्थिर तरीके नहीं हो सकता है का सवाल है ।
स्कैफ़मैन

9

वास्तव में, आप स्थैतिक क्षेत्रों की घोषणा कर सकते हैं यदि वे लगातार हैं और संकलन समय में लिखे गए हैं।

class OuterClass {
    void foo() {
        class Inner{
            static final int a = 5; // fine
            static final String s = "hello"; // fine
            static final Object o = new Object(); // compile error, because cannot be written during compilation
        }
    }
}

8
  1. वर्ग प्रारंभिक अनुक्रम एक महत्वपूर्ण कारण है।

जैसे कि आंतरिक कक्षाएं संलग्न / बाहरी वर्ग की आवृत्ति पर निर्भर हैं, इसलिए आंतरिक वर्ग के प्रारंभ से पहले बाहरी वर्ग को आरंभ करने की आवश्यकता होती है।
यह वर्ग प्रारंभिक के बारे में जेएलएस का कहना है। हमें जिस बिंदु की आवश्यकता है वह है, क्लास टी को इनिशियलाइज़ किया जाएगा यदि

  • T द्वारा घोषित एक स्थिर फ़ील्ड का उपयोग किया जाता है और फ़ील्ड स्थिर चर नहीं है।

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

  1. यह कुछ बुनियादी नियमों का उल्लंघन होगाआप two casesnoob सामान से बचने के लिए अंतिम अनुभाग (से ) पर जा सकते हैं

एक बात के बारे में , जब कुछ यह होता है तो हर तरह से एक सामान्य वर्ग की तरह व्यवहार करेगा और यह बाहरी वर्ग के साथ जुड़ा हुआ है।static nested classnested classstatic

लेकिन Inner class/ की अवधारणा बाहरी / संलग्न वर्ग के साथ जुड़ी होगी । कृपया ध्यान दें साथ जुड़े उदाहरण नहीं वर्ग। अब उदाहरण के साथ जुड़ने का स्पष्ट अर्थ है कि ( उदाहरण चर की अवधारणा से ) यह एक उदाहरण के अंदर मौजूद होगा और उदाहरणों के बीच अलग होगा। non-static nested classinstance

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

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

  • यदि इसे आंतरिक वर्ग के सभी उदाहरणों के साथ साझा किया जाता है तो यह context of instance(उदाहरण चर) की अवधारणा का उल्लंघन होगा । यह तो नहीं है।
  • यदि इसे सभी उदाहरणों के साथ साझा नहीं किया जाता है तो यह स्थिर होने की अवधारणा का उल्लंघन करेगा। फिर से नहीं।

5

यहां वह प्रेरणा है जो मुझे इस "सीमा" के लिए सबसे उपयुक्त लगती है: आप बाहरी वर्ग के उदाहरण क्षेत्र के रूप में एक आंतरिक वर्ग के स्थैतिक क्षेत्र के व्यवहार को लागू कर सकते हैं; इसलिए आपको स्थैतिक क्षेत्रों / विधियों की आवश्यकता नहीं है । मेरा अभिप्राय यह है कि किसी वस्तु (या विधि) के किसी वस्तु के सभी आंतरिक वर्ग उदाहरण साझा करते हैं।

तो, मान लीजिए कि आप सभी आंतरिक वर्ग उदाहरणों को गिनना चाहते हैं, तो आप ऐसा करेंगे:

public class Outer{
    int nofInner; //this will count the inner class 
                  //instances of this (Outer)object
                  //(you know, they "belong" to an object)
    static int totalNofInner; //this will count all 
                              //inner class instances of all Outer objects
    class Inner {
        public Inner(){
            nofInner++;
            totalNofInner++;
        }
    }
}

2
लेकिन सवाल यह है कि जब उन्हें घोषित किया जाता है finalतो स्थैतिक क्षेत्रों को अनुमति देने का क्या कारण है ?
सोलस

यदि आप [ stackoverflow.com/a/1954119/1532220] (ऊपर ऑस्कररायज़ जवाब देते हैं) को देखते हैं: उनकी प्रेरणा यह है कि एक मान वैरिएबल से जुड़ा नहीं हो सकता। बेशक, यदि चर अंतिम है, तो आप आसानी से जान सकते हैं कि किस मूल्य को निर्दिष्ट करना है (आपको पता होना चाहिए)।
इयोनोस

2

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

नोट: आंतरिक कक्षाओं को हमेशा बाहरी वर्ग के लिए एक चर की तरह मानते हैं, वे किसी भी अन्य चर की तरह स्थिर या गैर-स्थिर हो सकते हैं।


लेकिन भीतर के वर्ग में static finalनिरंतरता हो सकती है ।
बारिश


1

क्योंकि यह "स्थिर" के अर्थ में अस्पष्टता का कारण होगा।

आंतरिक कक्षाएं संकलन-समय स्थिरांक के अलावा स्थिर सदस्यों की घोषणा नहीं कर सकती हैं। "स्थिर" के अर्थ के बारे में अस्पष्टता होगी। क्या इसका मतलब है कि वर्चुअल मशीन में केवल एक ही उदाहरण है? या केवल एक उदाहरण प्रति बाहरी वस्तु? भाषा डिजाइनरों ने इस मुद्दे से निपटने का फैसला नहीं किया।

के। एस। होर्स्टमन द्वारा "कोर जावा एसई 9 द इम्पाटेंट" के लिए लिया गया। पृष्ठ 90 अध्याय 2.6.3


-1

मुझे लगता है कि यह स्थिरता के लिए है। हालांकि इसके लिए कोई तकनीकी सीमा नहीं लगती है, लेकिन आप आंतरिक वर्ग के स्थिर सदस्यों को बाहर से प्रवेश नहीं कर पाएंगे, OuterClass.InnerClass.iक्योंकि मध्य चरण स्थिर नहीं है।


लेकिन भीतर के वर्ग में static finalनिरंतरता हो सकती है ।
बारिश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.