从内部类对象获取外部类对象

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

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

165774 次浏览

在内部类本身中,可以使用OuterClass.this。这个表达式允许引用任何词法上封闭的实例,在JLS中被描述为合格this

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

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

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

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

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

OuterClass.this引用外部类。

你可以(但不应该)使用反射来完成这项工作:

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

当然,暗指的名字是完全不可靠的,所以如我所说,你不应该:-)

下面是例子:

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

这个问题的更一般的答案涉及阴影变量以及如何访问它们。

在下面的例子中(来自Oracle), main ()中的变量x遮蔽了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();
}
}

运行这个程序将输出:

x=0, Test.this.x=1

更多信息见:http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

如果您无法控制修改内部类,反射可能会帮助您(但不推荐)。这个$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);
}

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