Подтвердить что ты не робот

В Java, как мне получить доступ к внешнему классу, когда я не во внутреннем классе?

Если у меня есть экземпляр внутреннего класса, как я могу получить доступ к внешнему классу из кода, который не находится во внутреннем классе? Я знаю, что во внутреннем классе я могу использовать Outer.this для получения внешнего класса, но я не могу найти внешний способ его получения.

Например:

public class Outer {
  public static void foo(Inner inner) {
    //Question: How could I write the following line without
    //  having to create the getOuter() method?
    System.out.println("The outer class is: " + inner.getOuter());
  }
  public class Inner {
    public Outer getOuter() { return Outer.this; }
  }
}
4b9b3361

Ответ 1

Байт-код класса Outer$Inner будет содержать поле с областью пакета с именем this$0 типа Outer. Это то, что нестатические внутренние классы реализованы в Java, потому что на уровне байт-кода нет понятия внутреннего класса.

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

Вот как выглядит ваш пример кода при использовании отражения. Человек, это уродливо.;)

public class Outer {
    public static void foo(Inner inner) {
        try {
            Field this$0 = inner.getClass().getDeclaredField("this$0");
            Outer outer = (Outer) this$0.get(inner);
            System.out.println("The outer class is: " + outer);

        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public class Inner {
    }

    public void callFoo() {
        // The constructor of Inner must be called in 
        // non-static context, inside Outer.
        foo(new Inner()); 
    }

    public static void main(String[] args) {
        new Outer().callFoo();
    }
}

Ответ 2

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

Ответ 3

Что случилось с добавлением getter, когда вам нужно получить доступ к внешнему классу? Таким образом, вы можете контролировать, разрешен ли доступ или нет.

Ответ 4

Это, на самом деле, очень хороший вопрос, если, например, вам нужно проверить, имеют ли два разных экземпляра класса Innner один и тот же экземпляр класса Outer ( == или равно в зависимости от контекста).

Я бы предложил сделать интерфейс общего назначения (не совсем необходимый для названных внутренних классов, но может быть "instancedof" /casted to):

public interface InnerClass<Outer> {
    Outer getOuter();
}

который может быть применен к любому именованному внутреннему классу.

Затем вы делаете что-то вроде:

class MyInnerClass implements InnerClass<Outer> {
    Outer getOuter() {
        return Outer.this;
    }
    // remaining implementation details
}

и таким образом вы можете получить доступ к внешнему классу из любого внутреннего класса, реализующего интерфейс InnerClass<Outer> (и проверить его на самом деле реализует).

Если ваш внутренний класс анонимен, вы можете сделать это (благодаря Rich MacDonald для своего образца):

new InterfaceOrAbstractClass<Outer>() {
    Outer getOuter() { // super inefficient but this is the only way !
        return (Outer)getClass().getDeclaredField("this$0");
    }
    /* other methods */
}

но InterfaceOrAbstractClass должен внедрять InnerClass<Outer>, чтобы иметь доступ к getOuter() вне тела анонимного класса!

Было бы намного проще, если бы javac автоматически реализовал какой-то интерфейс InnerClass<Outer> во всех внутренних классах, и он мог бы сделать это супер эффективно даже на анонимных классах (без вялой обработки интроспекции)!

Ответ 5

Если у вас есть (нестатический) внутренний класс, то вы по определению работаете с чем-то, что работает только внутри окружающего контекста внешнего класса. Таким образом, чтобы получить дескриптор внутреннего класса, вам уже пришлось бы получить его через внешний экземпляр. Таким образом, единственный способ увидеть, что вам нужен такой аксессуар, - это захватить внутреннее внешнее ref, а затем потерять или отбросить ссылку на внешний экземпляр.

Например:

public class Outer{ 
   public class Inner {
   }
}

public class UsesInner{
 Collection<Outer.Inner> c = new ArrayList<Outer.Inner>();
}

Теперь единственный способ, которым вы можете заполнить c, - создать экземпляры Outer(). Мне было бы интересно увидеть полезную цель для чего-то вроде этого.

Ответ 6

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

Для записи используется "inner.getClass(). getDeclaredField (" this $0 ")". Поскольку поле является приватным, вам также необходимо вызвать field.setAccessible(true).

Ответ 7

Где проблема просто написать это?

class OuterClass{
class InnerClass{
    OuterClass outerClass = OuterClass.this;
}

}

Ответ 8

Разве вы не можете сделать что-то вроде этого:

public static class Inner { // static now
    private final Outer parent;

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

    public Outer get Outer() { return parent; }
}