English 中文(简体)
Getting hold of the outer class object from the inner class object
原标题:

I have the following code. I want to get hold of the outer class object using which I created the inner class object inner. How can I do it?

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 :-( ");
        }
    }
}

EDIT: Well, some of you guys suggested of modifying the inner class by adding a method:

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

But what if I don t have control to modify the inner class, then (just to confirm) do we have some other way of getting the corresponding outer class object from the inner class object?

最佳回答

Within the inner class itself, you can use OuterClass.this. This expression, which allows to refer to any lexically enclosing instance, is described in the JLS as Qualified this.

I don t think there s a way to get the instance from outside the code of the inner class though. Of course, you can always introduce your own property:

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

EDIT: By experimentation, it looks like the field holding the reference to the outer class has package level access - at least with the JDK I m using.

EDIT: The name used (this$0) is actually valid in Java, although the JLS discourages its use:

The $ character should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems.

问题回答

OuterClass.this references the outer class.

You could (but you shouldn t) use reflection for the job:

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);
    }
}

Of course, the name of the implicit reference is utterly unreliable, so as I said, you shouldn t :-)

The more general answer to this question involves shadowed variables and how they are accessed.

In the following example (from Oracle), the variable x in main() is shadowing Test.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();
    }
}

Running this program will print:

x=0, Test.this.x=1

More at: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

Here s the example:

// 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";
   }
}

if you don t have control to modify the inner class, the refection may help you (but not recommend). this$0 is reference in Inner class which tells which instance of Outer class was used to create current instance of Inner class.

/**
 * 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);
}

Of course, the name of the implicit reference is unreliable, so you shouldn t use reflection for the job.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签