Доступ к экземпляру внешнего класса с использованием экземпляра вложенного класса, хранящегося в переменной?

Рассмотрим следующие классы:

public class A {
    public int a;

    public class B {
         public int b;

         public void foo() {
             System.out.println(A.this.a);
             System.out.println(this.b);
         }
    }
}

В foo я обращаюсь к внешнему экземпляру A изнутри B, используя синтаксис A.this. Это хорошо работает, потому что я пытаюсь получить доступ к внешнему экземпляру A из «текущего объекта» в B. Однако что мне делать, если я хочу получить доступ к внешнему объекту A из переменной типа B?

public class A {
    public int a;

    public class B {
         public int b;

         public void foo(B other) {
             System.out.println(other.A.this.a); // <-- This is (obviously) wrong. What SHOULD I do here?
             System.out.println(other.b);
         }
    }
}

Каков правильный синтаксис для доступа к «внешнему» экземпляру из «внутреннего» экземпляра other в foo?

Я понимаю, что могу получить доступ к внешней переменной a, используя просто other.a. Прошу простить надуманный пример! Я просто не мог придумать лучшего способа спросить, как связаться с other.A.this.


person sigpwned    schedule 11.03.2014    source источник


Ответы (2)


Насколько я могу судить из спецификации языка Java, в Java нет синтаксиса для такого доступа. Вы можете обойти это, предоставив свой собственный метод доступа:

public class A {
    public int a;

    public class B {
         public int b;
         // Publish your own accessor
         A enclosing() {
             return A.this;
         }
         public void foo(B other) {
             System.out.println(other.enclosing().a);
             System.out.println(other.b);
         }
    }
}
person Sergey Kalinichenko    schedule 11.03.2014
comment
Отличный обходной путь. Я использую его сейчас. Если в течение следующего часа никто не вытащит кролика из шляпы, я соглашусь. Благодарю вас! - person sigpwned; 11.03.2014

Ну, вы не можете сделать это напрямую, так как в языке Java такой способ не определен. Однако вы можете использовать некоторые приемы отражения, чтобы получить значение этого поля.

По сути, внутренние классы хранят ссылку на объемлющий класс в поле с именем this$0. Вы можете найти более подробную информацию в этот другой пост на SO.

Теперь, используя отражение, вы можете получить доступ к этому полю и получить значение любого атрибута для этого поля:

class A {
    public int a;

    public A(int a) { this.a = a; }

    public class B {
         public int b;

         public B(int b) { this.b = b; }

         public void foo(B other) throws Exception {
             A otherA = (A) getClass().getDeclaredField("this$0").get(other); 
             System.out.println(otherA.a);
             System.out.println(other.b);
         }
    }
}

public static void main (String [] args) throws Exception {
    A.B obj1 = new A(1).new B(1);
    A.B obj2 = new A(2).new B(2);
    obj2.foo(obj1);
}

Это напечатает 1, 1.

Но, как я уже сказал, это всего лишь хак. Вы бы не хотели писать такой код в реальном приложении. Скорее, вам следует пойти более чистым путем, как показано в ответе @dashblinkenlight.

person Rohit Jain    schedule 11.03.2014