Dış sınıf nesnesinin iç sınıf nesnesinden tutulması


245

Takip koduna sahibim. İç sınıf nesnesini yarattığım dış sınıf nesnesini tutmak istiyorum inner. Nasıl yapabilirim?

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 :-( ");
        }
    }
}

EDIT: Eh, bazılarınız bir yöntem ekleyerek iç sınıfı değiştirmeyi önerdi:

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

Ama iç sınıfı değiştirmek için kontrolüm yoksa, o zaman (sadece onaylamak için) iç sınıf nesnesinden karşılık gelen dış sınıf nesnesini almanın başka bir yoluna sahip miyiz?

Yanıtlar:


329

İç sınıfın içinde kullanabilirsiniz OuterClass.this. Sözcük olarak çevreleyen herhangi bir örneğe gönderme yapılmasına izin veren bu ifade, JLS'de Niteliklithis olarak tanımlanır .

Ben yok düşünüyorum gerçi iç sınıfın kod dışından örneği almanın bir yolu var. Tabii ki, her zaman kendi mülkünüzü tanıtabilirsiniz:

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

DÜZENLEME: Deneme ile, dış sınıfa referans tutan alan paket düzeyinde erişim var gibi görünüyor - en azından ben kullanıyorum JDK ile.

DÜZENLEME: (kullanılan isim this$0) olduğu halde, Java aslında geçerli JLS kullanım için hayal kırıklığı:

$Karakter Eski sistemlerde, erişim önceden varolan isimlere, nadiren mekanik olarak oluşturulan kaynak kodu yalnızca kullanılan veya edilmelidir.


Teşekkürler Jon! Ama iç sınıfı değiştirmek için kontrole sahip değilsem (düzenlememi kontrol et).
peakit

7
@peakit: O zaman bildiğim kadarıyla, yansıma kullanmazsan şansın kalmaz. Gerçekten de bir kapsülleme ihlali gibi hissediyor - eğer iç sınıf size dış örneğinin ne olduğunu söylemek istemiyorsa, buna saygı duymalı ve ihtiyacınız olmayacak şekilde tasarlamaya çalışmalısınız.
Jon Skeet

1
Bu Java 8'de hala geçerli mi?
puslu

@misty Evet, öyle.
Hatefiend

36

OuterClass.this dış sınıfa başvurur.


7
Ancak yalnızca OuterClass kaynağının içinde / içinde. Ve OP'nin bunu istediğini sanmıyorum.
Stephen C

23

İş için yansımayı kullanabilirsiniz (ancak kullanmamalısınız):

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

Tabii ki, örtük referansın adı tamamen güvenilmez, bu yüzden dediğim gibi, yapmamalısınız :-)


2

Bu sorunun daha genel yanıtı gölgeli değişkenleri ve bunlara nasıl erişildiğini içerir.

(Oracle) Aşağıdaki örnekte, değişken X de , ana () gölgelendirme olan 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();
    }
}

Bu programı çalıştırmak yazdırır:

x=0, Test.this.x=1

Daha fazla bilgi için: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6


Örneğin, "Test.this.x" statik olduğundan, gerçekte kapalı sınıf nesnesine ait olmadığından "Test.this.x" ile aynı olduğu için bu noktanın en iyi sonucu verdiğinden emin değilsiniz. Kod statik değil Test sınıfı ve Test.x yapıcısında olsaydı daha iyi örnek olacağını düşünüyorum.
sb4

0

İşte örnek:

// 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

Eğer iç sınıfı değiştirmek için kontrolünüz yoksa, reddetme size yardımcı olabilir (ama tavsiye etmemektedir). bu $ 0, Inner sınıfının geçerli örneğini oluşturmak için hangi Outer sınıfı örneğinin kullanıldığını söyleyen Inner sınıfındaki başvurudır.


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

Tabii ki, örtük başvurunun adı güvenilir değildir, bu nedenle iş için yansıma kullanmamalısınız.


'Statik iç', bir çelişki.
Lorne Marquis,

-2

2020-06-15 tarihinde düzenlendi

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 :-( ");
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.