Два вопроса о внутренних классах в Java (класс A {класс B {}})

Извините за плохое название, но я не мог придумать лучшего.

У меня есть класс A и класс B, который является своего рода подклассом A, например:

(Есть ли для него правильное название? Разве «подкласс» не зарезервирован для наследования?)

class A {
    int i = 0;
    class B {
        int j = 1;
    }
}

class Test {
    public static void main() {
        A a = new A();
        B b = a.new B();
        A c = ??? b ??? // get "a" back
    }
}

Из B можно получить доступ к каждому свойству A, поэтому оба, a.i и b.i, возвращают 0. Теперь мне интересно, возможно ли каким-то образом получить исходный объект типа A из b, поскольку b содержит все, что содержит a? Очевидно, что простой кастинг не помогает.

Второй:

class A {

    void print() {
        System.out.println("This is class A.");
    }

    class B {
        void print() {
            // <--- How to access print() of class A (like this.A.print() or smth)? 
            System.out.println("This is class B.");
        }
    }
}

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

Заранее спасибо. :)

Я считаю, что правильное имя - внутренний класс.

tvanfosson 04.12.2008 03:35

Я считаю, что это дубликат этого вопроса (stackoverflow.com/questions/309737/…)

Dan Dyer 04.12.2008 03:38

на самом деле я всегда снова забываю об этом синтаксисе "classname.this" :)

Johannes Schaub - litb 04.12.2008 04:09

A c = b.this$0; работает? <- Не делай этого !!

Tom Hawtin - tackline 04.12.2008 17:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
6
4
17 121
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

[Обновлено: мой ответ подходит для программистов на C#, но я не могу гарантировать, что он применим к Java.]

B - это внутренний класс, а не подкласс A. Кроме того, B не содержит экземпляра A, поэтому ваш код как есть не может вернуть ни один экземпляр A.

Вам необходимо реструктурировать свои классы следующим образом:

class A
{
    public class B
    {
       public A Parent;
       public B(A parent)
       {
          this.Parent = parent;
       }
    }
}

Теперь у вашего класса B есть поле «Родитель», которое возвращает своего родителя. Вы можете использовать эти классы следующим образом (это синтаксис C#, потому что я не знаю, есть ли в Java другой синтаксис для создания экземпляров внутренних классов):

public static void Main(String[] args)
{
    A parent = new A();
    A.B child = new A.B(child);
    A backToParent = child.Parent;
}

Конечно, создание класса B таким способом кажется немного забавным: технически вы можете передать любого родителя. Вероятно, было бы лучше переписать ваш класс A с помощью метода, который возвращает B:

class A
{        
    public class B
    {
       public A Parent;
       public B(A parent)
       {
          this.Parent = parent;
       }
    }

    public B getChild()
    {
        return new B(this);
    }
}

public static void Main(String[] args)
{
    A parent = new A();
    A.B child = A.getChild();
    A backToParent = child.Parent;
}

Фактически, он содержит экземпляр A. См. Также: stackoverflow.com/questions/309737/… Тем не менее, спасибо за ваш ответ. То, что вы описали, безусловно, является другим решением.

balu 04.12.2008 03:54

Кажется, что «внутренний класс» относится к другому понятию, чем в Java (примерно то, что Java назвала бы «вложенным классом»).

Tom Hawtin - tackline 04.12.2008 17:18
Ответ принят как подходящий

Кажется, нет способа получить доступ к внешнему классу извне. Но сделать это можно так:

class A {
    int i = 0;
    class B {
        final A outer = A.this;
        int j = 1;
    }
}

class Test {
    public static void main() {
        A a = new A();
        A.B b = a.new B();
        A c = b.outer // get "a" back
    }
}

ClassName.this будет экземпляром внешнего класса, связанного с экземпляром внутреннего класса.

Я думаю, что B b = ... неверно. Вы не можете объявить ссылку типа B без использования A. A.B b = ... Было бы лучше ..

OscarRyz 04.12.2008 04:00

Я бы сделал заявление final A outer = A.this; на всякий случай

Bill Michell 04.12.2008 13:23

Более элегантное решение - предоставить такой метод, как external (), для возврата A. this, чтобы сохранить добавление поля.

Peter Lawrey 03.05.2009 14:01

Добавление поля не только тратит впустую пространство, но и создает круговую зависимость, которую сборщику мусора гораздо сложнее очистить.

Peter Lawrey 03.05.2009 14:05

@ Питер Лоури: добавление final A external = A. это к внутреннему классу B в любом случае происходит неявно. Йоханнес просто разъясняет это прямо. Проверить дизассемблированный класс A $ B.class без конечной внешней переменной:> javap A $ B Скомпилирован из максимума класса "A.java". $ B расширяет java.lang.Object {int j; итоговая максима.А это $ 0; максим.A $ B (максим.A); }

Max 10.07.2010 09:04

@Max, я согласен, что вы получаете это поле $ 0 бесплатно, поэтому вам не нужно явное поле, чтобы делать то, что java делает для вас в любом случае. Не уверен, почему сделать поле явным более ясным, чем использование метода для возврата того же значения.

Peter Lawrey 12.07.2010 23:41

Спасибо за ваш вклад. Первый пример - это именно то, что я искал (доступ к оригинал) внешнего класса из внутреннего

Domenic D. 15.08.2012 06:57

Вы можете получить к нему доступ с помощью синтаксиса ParentClass.this из внутреннего класса.

например

public class Outter
{
    class Inner {
        public Outter getOutter()
        {
            return Outter.this;
        }
    }

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

class Runner{
    public static void main(String[] args){
        Outter out = new Outter(); 
        Outter.Inner inner = out.getInner();

        System.out.println(inner.getOutter().toString());
    }
}

это, казалось, сработало для меня

class A {
    int i = 0;
    class B {
        int j = 1;
    }
}

class Test {
    public static void main() {
        A a = new A();
        A.B b = a.new B();
        A c = (A)b.getClass().getDeclaredField("this$0").get(b);
    }
}

Другие вопросы по теме