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


245

我有以下代码。我想掌握用来创建内部类对象的外部类对象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;
}

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

Answers:


329

在内部类本身内,您可以使用OuterClass.this。此表达式允许引用任何词法包围的实例,在JLS中称为Qualifiedthis

认为没有办法从内部类的代码之外获取实例。当然,您可以随时介绍自己的财产:

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

编辑:通过实验,看起来对外部类的引用的引用字段具有包级别的访问权限-至少与我正在使用的JDK一样。

编辑:使用(这个名字this$0在Java中确实有效,虽然JLS阻碍了它的用法:

$字符仅应在机械生成的源代码中使用,或很少用于访问旧系统上的现有名称。


谢谢乔恩!但是,如果我没有控制权来修改内部类(检查我的编辑)怎么办。
09年

7
@peakit:据我所知,除非使用反射,否则您很不走运。感觉确实确实违反了封装-如果内部类不想告诉您外部实例是什么,则应尊重这一点并尝试进行设计以使您不需要它。
乔恩·斯基特

1
这在Java 8中仍然有效吗?
朦胧的

@misty是的。
哈特菲德

36

OuterClass.this 引用外部类。


7
但仅在外部类的源之内/之内。而且我不认为这是OP想要的。
Stephen C

23

您可以(但不应)对工作使用反射:

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

当然,隐式引用的名称是绝对不可靠的,因此正如我所说,您不应该:-)


2

这个问题的更一般的答案涉及阴影变量及其访问方式。

在下面的例子(从Oracle),变量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


不确定该示例是否证明了最佳点,因为“ Test.this.x”与“ Test.x”相同,因为它是静态的,并不真正属于封闭的类对象。我认为如果代码在Test和Test.x类的构造函数中不是静态的,那将是一个更好的示例。
sb4

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

0

如果您没有控制权来修改内部类,那么重新编写便会有所帮助(但不建议这样做)。this $ 0是Inner类中的引用,它指示使用Outer类的哪个实例创建Inner类的当前实例。


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

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


“静态内部”是一个矛盾。
罗恩侯爵,

-2

已于2020-06-15进行编辑

public class Outer {

    public Inner getInner(){
        return new Inner(this);
    }

    static class Inner {

        public final Outer Outer;

        public Inner(Outer outer) {
            this.Outer=outer;
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.getInner();
        Outer anotherOuter=inner.Outer;

        if(anotherOuter == outer) {
            System.out.println("Was able to reach out to the outer object via inner !!");
        } else {
            System.out.println("No luck :-( ");
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.