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

时间:2009-11-29 19:10:18

标签: java inner-classes

我有以下代码。我想抓住外部类对象,使用它创建内部类对象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;
}

但是如果我没有控制来修改内部类,那么(只是为了确认)我们还有其他方法从内部类对象中获取相应的外部类对象吗?

9 个答案:

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

当然,隐式引用的名称是不可靠的,因此您不应在工作中使用反射。