我有下面的代码。我想获得外部类对象,我使用它创建了内部类对象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;
}

但是如果我没有修改内部类的控制,那么(只是确认一下)我们是否有其他方法从内部类对象中获得相应的外部类对象?


当前回答

下面是例子:

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

其他回答

下面是例子:

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

在内部类中,你可以使用outerclass。这个表达式允许引用任何词法上封闭的实例,在JLS中被描述为Qualified This。

不过,我认为没有办法从内部类的代码之外获取实例。当然,你也可以随时介绍自己的物业:

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

编辑:通过实验,保存外部类引用的字段似乎具有包级访问权限——至少在我使用的JDK中是这样。

编辑:使用的名称(这个$0)在Java中实际上是有效的,尽管JLS不鼓励使用它:

$字符只能在 机械生成的源代码或, 很少访问已存在的名称 遗留系统。

OuterClass。这引用了外部类。

如果您无法控制修改内部类,反射可能会帮助您(但不推荐)。这个$0是内部类中的引用,它告诉外部类的哪个实例被用于创建内部类的当前实例。

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

当然,隐式引用的名称是不可靠的,所以您不应该使用反射来完成这项工作。