Getting hold of the outer class object from the inner class object
我有以下代码。我想了解创建内部类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 :-("); } } } |
编辑:好吧,你们中的一些人建议通过添加一个方法来修改内部类:
1 2 3 | public OuterClass outer() { return OuterClass.this; } |
号
但是如果我没有修改内部类的控制权,那么(只是确认一下)我们是否有其他方法从内部类对象中获取相应的外部类对象呢?
在内部类本身中,可以使用
不过,我认为没有办法从内部类的代码之外获取实例。当然,您可以随时介绍自己的财产:
1 2 3 | public OuterClass getOuter() { return OuterClass.this; } |
编辑:通过实验,保存对外部类的引用的字段似乎具有包级访问权限——至少对于我使用的JDK是这样的。
编辑:使用的名称(EDCOX1(2))在Java中实际上是有效的,尽管JLS阻止了它的使用:
The
$ character should be used only in
mechanically generated source code or,
rarely, to access pre-existing names on
legacy systems.
号
你可以(但不应该)用反省来做这份工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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); } } |
号
当然,隐式引用的名称是完全不可靠的,所以如我所说,您不应该:—)
这个问题的更一般的答案涉及隐藏变量以及如何访问它们。
在下面的示例中(来自Oracle),main()中的变量x正在隐藏test.x:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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(); } } |
运行此程序将打印:
1 | x=0, Test.this.x=1 |
。
更多信息,请访问:http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html jls-6.6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /** * 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); } |
当然,隐式引用的名称是不可靠的,因此您不应该为该作业使用反射。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Outer { public Inner getInner(){ return new Inner(this,this.getClass()); } class Inner { public Inner(Outer outer, Class<? extends Outer> aClass) { System.out.println(outer); System.out.println(aClass.getName()); System.out.println(); } } public static void main(String[] args) { new Outer().getInner(); } } |
。
如果您没有修改内部类的控件,那么refection可能会帮助您(但不推荐)。这个$0是内部类中的引用,它告诉外部类的哪个实例被用来创建内部类的当前实例。
我就是这样做的:
1 2 3 4 5 6 7 | public class CherryTree { public class Cherry { public final CherryTree cherryTree = CherryTree.this; // [...] } // [...] } |
。
当然,您需要能够修改内部类,并且每个获得内部类对象的人现在都可以访问外部类对象。就我而言,一切都很好。
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |