आंतरिक वर्ग वस्तु से बाहरी वर्ग वस्तु को पकड़ना


245

मेरे पास निम्न कोड है। मैं बाहरी वर्ग की वस्तु को पकड़ना चाहता हूं जिसके उपयोग से मैंने आंतरिक वर्ग वस्तु बनाई inner। मैं यह कैसे कर सकता हूं?

public class OuterClass {

    public class InnerClass {
        private String name = "Peakit";
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        InnerClass inner = outer.new InnerClass();
       // How to get the same outer object which created the inner object back?
        OuterClass anotherOuter = ?? ;

        if(anotherOuter == outer) {
             System.out.println("Was able to reach out to the outer object via inner !!");
        } else {
             System.out.println("No luck :-( ");
        }
    }
}

संपादित करें: ठीक है, आप में से कुछ लोगों ने एक विधि जोड़कर आंतरिक वर्ग को संशोधित करने का सुझाव दिया:

public OuterClass outer() {
   return OuterClass.this;
}

लेकिन क्या होगा अगर मेरे पास आंतरिक वर्ग को संशोधित करने के लिए नियंत्रण नहीं है, तो (केवल पुष्टि करने के लिए) क्या हमारे पास आंतरिक वर्ग वस्तु से संबंधित बाहरी वर्ग वस्तु प्राप्त करने का कोई अन्य तरीका है?

जवाबों:


329

भीतर की कक्षा के भीतर, आप उपयोग कर सकते हैं OuterClass.this। यह अभिव्यक्ति, जो किसी लेक्सिक रूप से संलग्न उदाहरण को संदर्भित करने की अनुमति देती है, जेएलएस में योग्य केthis रूप में वर्णित है ।

मुझे नहीं लगता कि आंतरिक कक्षा के कोड के बाहर से उदाहरण प्राप्त करने का कोई तरीका है। बेशक, आप हमेशा अपनी खुद की संपत्ति पेश कर सकते हैं:

public OuterClass getOuter() {
    return OuterClass.this;
}

संपादित करें: प्रयोग से, ऐसा लगता है कि बाहरी वर्ग के संदर्भ को रखने वाले क्षेत्र में पैकेज स्तर की पहुंच है - कम से कम जेडीआई के साथ मैं उपयोग कर रहा हूं।

संपादित करें: इस्तेमाल किया (नाम this$0) है , वास्तव में जावा में मान्य हालांकि JLS इसके उपयोग को हतोत्साहित:

$चरित्र विरासत प्रणालियों पर पहुँच पहले से मौजूद नामों को यंत्रवत् उत्पन्न स्रोत कोड में ही प्रयोग किया जाता जाना चाहिए या, शायद ही कभी,।


धन्यवाद जॉन! लेकिन क्या होगा अगर मेरे पास आंतरिक वर्ग (मेरे संपादन की जांच) को संशोधित करने के लिए नियंत्रण नहीं है।
चोटी

7
@ पीकिट: जब तक मैं जानता हूं, आप भाग्य से बाहर हैं जब तक आप प्रतिबिंब का उपयोग नहीं करते हैं। ऐसा लगता है कि यह वास्तव में इनकैप्सुलेशन का उल्लंघन है - अगर आंतरिक वर्ग आपको यह नहीं बताना चाहता है कि इसका बाहरी उदाहरण क्या है, तो आपको इसका सम्मान करना चाहिए और ऐसे डिजाइन करने का प्रयास करना चाहिए, जिसकी आपको आवश्यकता नहीं है।
जॉन स्कीट

1
क्या यह अभी भी जावा 8 में मान्य है?
मिस्टी

@ मिस्टी हाँ, यह है।
हेटफाइंड

36

OuterClass.this बाहरी वर्ग का संदर्भ देता है।


7
लेकिन केवल OuterClass के स्रोत के भीतर /। और मुझे नहीं लगता कि ओपी चाहता है।
स्टीफन C

23

आप नौकरी के लिए प्रतिबिंब का उपयोग कर सकते हैं (लेकिन आपको नहीं करना चाहिए):

import java.lang.reflect.Field;

public class Outer {
    public class Inner {
    }

    public static void main(String[] args) throws Exception {

        // Create the inner instance
        Inner inner = new Outer().new Inner();

        // Get the implicit reference from the inner to the outer instance
        // ... make it accessible, as it has default visibility
        Field field = Inner.class.getDeclaredField("this$0");
        field.setAccessible(true);

        // Dereference and cast it
        Outer outer = (Outer) field.get(inner);
        System.out.println(outer);
    }
}

बेशक, निहित संदर्भ का नाम पूरी तरह से अविश्वसनीय है, इसलिए जैसा कि मैंने कहा, आपको नहीं करना चाहिए :-)


2

इस प्रश्न के अधिक सामान्य उत्तर में छायांकित चर शामिल हैं और वे कैसे एक्सेस किए जाते हैं।

निम्नलिखित उदाहरण में (ओरेकल से), मुख्य में चर x () टेस्ट कर रहा है। x :

class Test {
    static int x = 1;
    public static void main(String[] args) {
        InnerClass innerClassInstance = new InnerClass()
        {
            public void printX()
            {
                System.out.print("x=" + x);
                System.out.println(", Test.this.x=" + Test.this.x);
            }
        }
        innerClassInstance.printX();
    }

    public abstract static class InnerClass
    {
        int x = 0;

        public InnerClass() { }

        public abstract void printX();
    }
}

इस कार्यक्रम को चलाने से प्रिंट होगा:

x=0, Test.this.x=1

और अधिक: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6


सुनिश्चित नहीं है कि उदाहरण सबसे अच्छा साबित होता है क्योंकि "Test.this.x" "Test.x" के समान है क्योंकि यह स्थिर है, वास्तव में संलग्न वर्ग वस्तु से संबंधित नहीं है। मुझे लगता है कि बेहतर उदाहरण होगा अगर कोड क्लास टेस्ट और टेस्ट के कंस्ट्रक्टर में था। स्थिर नहीं।
sb4

0

यहाँ उदाहरण है:

// Test
public void foo() {
    C c = new C();
    A s;
    s = ((A.B)c).get();
    System.out.println(s.getR());
}

// classes
class C {}

class A {
   public class B extends C{
     A get() {return A.this;}
   }
   public String getR() {
     return "This is string";
   }
}

0

यदि आपके पास आंतरिक वर्ग को संशोधित करने के लिए नियंत्रण नहीं है, तो परिशोधन आपकी मदद कर सकता है (लेकिन अनुशंसा नहीं)। यह $ 0 इनर वर्ग का संदर्भ है जो बताता है कि इनर क्लास की वर्तमान आवृत्ति बनाने के लिए बाहरी वर्ग के किस उदाहरण का उपयोग किया गया था।


-1
/**
 * Not applicable to Static Inner Class (nested class)
 */
public static Object getDeclaringTopLevelClassObject(Object object) {
    if (object == null) {
        return null;
    }
    Class cls = object.getClass();
    if (cls == null) {
        return object;
    }
    Class outerCls = cls.getEnclosingClass();
    if (outerCls == null) {
        // this is top-level class
        return object;
    }
    // get outer class object
    Object outerObj = null;
    try {
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            if (field != null && field.getType() == outerCls
                    && field.getName() != null && field.getName().startsWith("this$")) {
                field.setAccessible(true);
                outerObj = field.get(object);
                break;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return getDeclaringTopLevelClassObject(outerObj);
}

बेशक, निहित संदर्भ का नाम अविश्वसनीय है, इसलिए आपको नौकरी के लिए प्रतिबिंब का उपयोग नहीं करना चाहिए।


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

-2

2020-06-15 में संपादित किया गया है

public class Outer {

    public Inner getInner(){
        return new Inner(this);
    }

    static class Inner {

        public final Outer Outer;

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

    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.getInner();
        Outer anotherOuter=inner.Outer;

        if(anotherOuter == outer) {
            System.out.println("Was able to reach out to the outer object via inner !!");
        } else {
            System.out.println("No luck :-( ");
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.