2009-04-18 19 views
32

यदि मेरे पास एक आंतरिक कक्षा का उदाहरण है, तो मैं बाहरी कक्षा को उस कोड से कैसे एक्सेस कर सकता हूं जो आंतरिक कक्षा में नहीं है? मुझे पता है कि आंतरिक वर्ग के भीतर, मैं बाहरी वर्ग प्राप्त करने के लिए Outer.this का उपयोग कर सकता हूं, लेकिन मुझे इसे प्राप्त करने का कोई बाहरी तरीका नहीं मिल रहा है।जावा में, जब मैं आंतरिक कक्षा में नहीं हूं, तो मैं बाहरी वर्ग तक कैसे पहुंच सकता हूं?

उदाहरण के लिए:

public class Outer { 
    public static void foo(Inner inner) { 
    //Question: How could I write the following line without 
    // having to create the getOuter() method? 
    System.out.println("The outer class is: " + inner.getOuter()); 
    } 
    public class Inner { 
    public Outer getOuter() { return Outer.this; } 
    } 
} 
+0

आप समझा सकता है कि समस्या क्या आप को हल करते हैं? या यह अकादमिक है? –

+0

अकादमिक, मुख्य रूप से। इसके जवाब में आने पर मैं इसे पार कर गया: http://stackoverflow.com/questions/763359/validating-instances-of-inner-classes/763504 मैंने दो जवाब दिए, एक ऐसा कर रहा था जो ओपी उपयोग करने के लिए कह रहा था मैं वही कामकाज ऊपर उपयोग करता हूं (एक getOuter() विधि)। लेकिन मेरे दूसरे उत्तर में (जिसे एक उखाड़ फेंक दिया गया है) मैंने इसे एक अलग तरीके से डिजाइन करने के लिए कहा ताकि यह आवश्यक न हो। लेकिन अगर मैं ऐसा करना संभव था तो मैं अभी भी उत्सुक था। – Kip

+1

आपका प्रदान किया गया उदाहरण इस प्रश्न का सबसे अच्छा जवाब है। – Pindatjuh

उत्तर

32

Outer$Inner कक्षा के बाइटकोड में नाम Outer नामक पैकेज-स्कोप्ड फ़ील्ड होगा। इस प्रकार जावा में गैर स्थैतिक आंतरिक कक्षाएं लागू की जाती हैं, क्योंकि बाइटकोड स्तर पर आंतरिक कक्षा की कोई अवधारणा नहीं होती है।

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

यहां बताया गया है कि प्रतिबिंब का उपयोग करते समय आपका उदाहरण कोड कैसा दिखाई देगा। मैन, वह बदसूरत है। ;)

public class Outer { 
    public static void foo(Inner inner) { 
     try { 
      Field this$0 = inner.getClass().getDeclaredField("this$0"); 
      Outer outer = (Outer) this$0.get(inner); 
      System.out.println("The outer class is: " + outer); 

     } catch (NoSuchFieldException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public class Inner { 
    } 

    public void callFoo() { 
     // The constructor of Inner must be called in 
     // non-static context, inside Outer. 
     foo(new Inner()); 
    } 

    public static void main(String[] args) { 
     new Outer().callFoo(); 
    } 
} 
+2

यह (आईआईआरसी) कंपाइलर निर्भर है, और आपको सामान्य रूप से एक सेट की आवश्यकता होगी। –

+0

मुझे लगता है (spec को देखने के लिए बहुत आलसी) यहां तक ​​कि उस फ़ील्ड का नामकरण भी कंपाइलर निर्भर है, इसलिए यदि आप किसी अन्य कंपाइलर के साथ हैक को आजमा सकते हैं तो आप संभवतः समस्या में भाग सकते हैं। –

+0

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

14

वहाँ कोई रास्ता नहीं है, डिजाइन कर रहा है। यदि आपको आंतरिक वर्ग के उदाहरण के माध्यम से बाहरी वर्ग तक पहुंचने की आवश्यकता है, तो आपका डिज़ाइन पिछड़ा है: आंतरिक कक्षाओं का बिंदु आमतौर पर केवल बाहरी वर्ग के भीतर या इंटरफ़ेस के माध्यम से उपयोग किया जाता है।

+2

यह मेरा विचार भी था, लेकिन मुझे इस सीमा को संबोधित करने वाले किसी दस्तावेज़ को प्रतीत नहीं होता है। यदि आप कुछ भी आधिकारिक पा सकते हैं तो मैं खुशी से इस जवाब को स्वीकार करूंगा। – Kip

+0

यह एक स्पष्ट "सीमा" नहीं है - किसी विशेष (बल्कि अस्पष्ट) सुविधा के ABSENCE के बारे में दस्तावेज़ क्यों होना चाहिए? –

+2

15.8.3 और 15.8.4 इसे शामिल करता है। "किसी भी शब्दावली से संलग्न उदाहरण को स्पष्ट रूप से कीवर्ड को अर्हता प्राप्त करके संदर्भित किया जा सकता है।" प्रश्न के मामले में, यह एक स्पष्ट रूप से संलग्न उदाहरण नहीं है। –

8

बाहरी कक्षा तक पहुंचने के लिए गेटटर जोड़ने में क्या गड़बड़ है? इस तरह आप नियंत्रित कर सकते हैं कि पहुंच की अनुमति है या नहीं।

0

तुम सिर्फ कुछ इस तरह नहीं कर सकते: परिभाषा से कुछ के साथ काम कर

public static class Inner { // static now 
    private final Outer parent; 

    public Inner(Outer parent) { this.parent = parent; } 

    public Outer get Outer() { return parent; } 
} 
+3

स्थैतिक निकालें, और उपयोग करें: बाहरी getOuter() {वापसी Outer.this; } –

1

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

उदाहरण के लिए:

public class Outer{ 
    public class Inner { 
    } 
} 

public class UsesInner{ 
Collection<Outer.Inner> c = new ArrayList<Outer.Inner>(); 
} 

अब एक ही रास्ता आप ग पॉप्युलेट कर सकती बाहरी() उदाहरणों बनाने के द्वारा है। मैं इस तरह के कुछ के लिए एक उपयोगी उद्देश्य देखने के लिए उत्सुक होगा।

+0

ईमानदारी से, मैं किसी भी अच्छे कारण के बारे में नहीं सोच सकता।मैं बस इस सवाल का जवाब देने की कोशिश कर रहा हूं: http://stackoverflow.com/questions/763359/validating-instances-of-inner-classes/763504 उस स्थिति में, वह यह सुनिश्चित करना चाहता था कि उसके पास एक आंतरिक वर्ग हो बाहरी वर्ग का विशिष्ट उदाहरण। मैंने एक और जवाब में सुझाव दिया कि उसे केवल आंतरिक वर्ग में विधि को परिभाषित करना चाहिए ताकि यह कोई समस्या न हो। लेकिन, फिर से, अगर मैं ऐसा करने का कोई तरीका उत्सुक था। – Kip

1

यहां एक कारण है कि आप इस व्यवहार को चाहते हैं: आपके पास आंतरिक वर्ग का उदाहरण है और प्रतिबिंब का उपयोग करके बाहरी वर्ग में परिभाषित विधि तक पहुंचने की आवश्यकता है।

रिकॉर्ड के लिए, "inner.getClass()। GetDeclaredField (" यह $ 0 ")" काम करता है। चूंकि फ़ील्ड निजी है, इसलिए आपको field.setAccessible (true) को कॉल करने की भी आवश्यकता है।

6

यह, वास्तव में, एक बहुत अच्छा सवाल है, तो, उदाहरण के लिए, आप एक Innner वर्ग हिस्से की दो अलग-अलग उदाहरणों Outer वर्ग (== का एक ही उदाहरण या संदर्भ के आधार पर बराबर अगर जाँच करने के लिए सक्षम होना चाहिए है)।

मैं एक सामान्य प्रयोजन इंटरफ़ेस बनाने के लिए सुझाव देंगे (बिल्कुल नामित इनर क्लासों के लिए आवश्यक नहीं है, लेकिन "instancedof"/करने के लिए casted जा सकता है):

public interface InnerClass<Outer> { 
    Outer getOuter(); 
} 

है कि किसी भी नामित भीतरी वर्ग के लिए लागू किया जा सकता ।

तो फिर तुम जैसे कुछ कार्य करें:

class MyInnerClass implements InnerClass<Outer> { 
    Outer getOuter() { 
     return Outer.this; 
    } 
    // remaining implementation details 
} 

और इस तरह से आप किसी भी भीतरी वर्ग InnerClass<Outer> इंटरफेस को लागू करने से बाहरी वर्ग का उपयोग (और जाँच यह वास्तव में यह लागू करता है) कर सकते हैं।

तो अपने भीतर के वर्ग अनाम है, आप केवल (अपने नमूने के लिए रिच मैकडोनाल्ड करने के लिए धन्यवाद) कर सकते हैं:

new InterfaceOrAbstractClass<Outer>() { 
    Outer getOuter() { // super inefficient but this is the only way ! 
     return (Outer)getClass().getDeclaredField("this$0"); 
    } 
    /* other methods */ 
} 

लेकिन InterfaceOrAbstractClassचाहिएInnerClass<Outer> लागू करता है गुमनाम की getOuter() बाहर तक पहुँचने के लिए सक्षम होने के लिए कक्षा शरीर!

यदि जावा ने स्वचालित रूप से सभी आंतरिक वर्गों पर InnerClass<Outer> इंटरफेस को स्वचालित रूप से कार्यान्वित किया तो यह बहुत आसान होगा, और यह अज्ञात वर्गों (कोई सुस्त आत्मनिरीक्षण प्रसंस्करण) पर भी सुपर कुशलता से ऐसा नहीं कर सकता है!

1

बस इसे लिखने की समस्या कहां है?

class OuterClass{ 
class InnerClass{ 
    OuterClass outerClass = OuterClass.this; 
} 

}

+4

जिस तरह से लिखा गया है, यह कहना मुश्किल है कि यह एक उत्तर है या एक नया सवाल है। – Eric

संबंधित मुद्दे

 संबंधित मुद्दे