我有以下代码。我想抓住外部类对象,使用它创建内部类对象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;
}
但是如果我没有控制来修改内部类,那么(只是为了确认)我们还有其他方法从内部类对象中获取相应的外部类对象吗?
答案 0 :(得分:298)
在内部类本身中,您可以使用OuterClass.this
。此表达式允许引用任何词汇封闭的实例,在JLS中描述为Qualified this
。
我不认为有一种方法可以从内部类的代码之外获取实例。当然,您可以随时介绍自己的房产:
public OuterClass getOuter() {
return OuterClass.this;
}
编辑:通过实验,看起来持有外部类引用的字段具有包级访问权限 - 至少使用我正在使用的JDK。
编辑:使用的名称(this$0
) 实际上在Java中有效,尽管JLS不鼓励使用它:
$
字符只能用于 机械生成的源代码或, 很少,访问预先存在的名称 遗留系统。
答案 1 :(得分:31)
OuterClass.this
引用外部类。
答案 2 :(得分:20)
你可以(但你不应该)使用反射来完成工作:
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);
}
}
当然,隐式引用的名称完全不可靠,正如我所说,你不应该: - )
答案 3 :(得分:2)
这个问题的更一般的答案涉及阴影变量及其访问方式。
在以下示例中(来自Oracle), main()中的变量 x 是阴影 Test.x :
mouseenter
运行此程序将打印:
myElement
更多信息:http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6
答案 4 :(得分: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";
}
}
答案 5 :(得分:0)
我就是这样做的:
public class CherryTree {
public class Cherry {
public final CherryTree cherryTree = CherryTree.this;
// [...]
}
// [...]
}
当然,您需要能够修改内部类,并且获取内部类对象的每个人现在都可以访问外部类对象。在我的情况下,它很好。
答案 6 :(得分:0)
如果您无法控制修改内部类,则反思可能对您有帮助(但不推荐)。这个$ 0是Inner类中的引用,它告诉我使用哪个Outer类实例来创建Inner类的当前实例。
答案 7 :(得分:0)
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();
}
}
答案 8 :(得分: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);
}
当然,隐式引用的名称是不可靠的,因此您不应在工作中使用反射。