Вложенные классы в Java

    image

    Добрый день, Хабровчане! Я уже довольно давно программирую на java, и нередко использую вложенные классы, но недавно наткнулся на статический вложенный класс и понял, что я о нем почти ничего не знаю. Поэтому я решил разобраться в этом, систематизировать свои знания, а заодно и поделиться этими знаниями с вами.

    Вложенный класс (InnerClass)


    public class OuterClass {
        public class InnerClass{
        }
    }

    Из него видны:
    — все (даже private) свойства и методы OuterClassа обычные и статические.
    — public и protected свойства и методы родителя OuterClassа обычные и статические. То есть те, которые видны в OuterClassе.

    Его видно:
    — согласно модификатору доступа.

    Может наследовать:
    — обычные классы.
    — такие же внутренние классы в OuterClassе и его предках.

    Может быть наследован:
    — таким же внутренним классом в OuterClassе и его наследниках.

    Может имплементировать интерфейс

    Может содержать:
    — только обычные свойства и методы (не статические).

    Экзэмпляр этого класса создаётся так:
    OuterClass outerClass = new OuterClass();
    OuterClass.InnerClass innerClass = outerClass.new InnerClass();


    Статический вложенный класс (StaticInnerClass)


    public class OuterClass {
        public static class StaticInnerClass{
        }
    }

    Из него (самого класса) видны:
    — статические свойства и методы OuterClassа (даже private).
    — статические свойства и методы родителя OuterClassа public и protected. То есть те, которые видны в OuterClassе.

    Из его экземпляра видны:
    — все (даже private) свойства и методы OuterClassа обычные и статические.
    — public и protected свойства и методы родителя OuterClassа обычные и статические. То есть те, которые видны в OuterClassе.

    Его видно:
    — согласно модификатору доступа.

    Может наследовать:
    — обычные классы.
    — такие же статические внутренние классы в OuterClassе и его предках.

    Может быть наследован:
    — любым классом:
    — вложенным
    — не вложенным
    — статическим
    не статическим!

    Может имплементировать интерфейс

    Может содержать:
    — статические свойства и методы.
    — не статические свойства и методы.

    Экзэмпляр этого класса создаётся так:
    OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();

    Локальный класс (LocalClass)


    public class OuterClass {
        public void someMethod(){
            class LocalClass{
            }
        }
    }

    Из него видны:
    — все (даже private) свойства и методы OuterClassа обычные и статические.
    — public и protected свойства и методы родителя OuterClassа обычные и статические. То есть те, которые видны в OuterClassе.

    Его видно:
    — только в том методе где он определён.

    Может наследовать:
    — обычные классы.
    — внутренние классы в OuterClassе и его предках.
    — такие же локальные классы определённые в том же методе.

    Может быть наследован:
    — таким же локальным классом определённом в том же методе.

    Может имплементировать интерфейс

    Может содержать:
    — только обычные свойства и методы (не статические).

    Анонимный класс (имени нет)


    Локальный класс без имени. Наследует какой-то класс, или имплиментирует какой-то интерфейс.

    public class OuterClass {
        public void someMethod(){
            Callable callable = new Callable() {
                @Override
                public Object call() throws Exception {
                    return null;
                }
            };
        }
    }

    Из него видны:
    — все (даже private) свойства и методы OuterClassа обычные и статические.
    — public и protected свойства и методы родителя OuterClassа обычные и статические. То есть те, которые видны в OuterClassе.

    Его видно:
    — только в том методе где он определён.

    Не может быть наследован

    Может содержать:
    — только обычные свойства и методы (не статические).

    На этом всё. Жду ваших комментариев: какие есть неточности и ошибки, что я не покрыл и т.п.
    Надеюсь, статья будет многим полезна.
    Поделиться публикацией

    Комментарии 13

      +1

      Интересно а почему нельзя создавать экземпляр статического вложенного класса? Не спец в java, но такие классы по идее должны быть подобны вложенным классам в с++ т.е. они используют объемлющий класс просто как пространство имен.

        0

        Вы это все прочитали? Поздравляю :-)


        Разумеется, создать экземпляр вложенного класса — можно. Кстати, из такого класса видны любые члены внешнего класса, а не только статические: https://ideone.com/U3c9Qb, так что тут у автора полная ерунда написана...

          0
          Чутка не успел. Аналогичный случай. ideone.com/N1Czmt
            0
            Уже исправил, Спасибо
              0
              А видимость нестатических членов внешнего класса почему не исправили?
                0
                Только что проверил
                public class OuterClass {
                    public String outerStr = "outerStr";
                    public static class StaticInner{
                        public static void staticInnerMethod(){
                            System.out.println(outerStr);
                        }
                        public void innerMethod(){
                            System.out.println(outerStr);
                        }
                    }
                }

                Обе строки «System.out.println(outerStr);» выдают ошибку.
                Если сделать outerStr статическим — всё работает нормально
                  +1

                  Дык это не видимость, а вы не указали объект. Должно быть что-то вроде
                  OuterClass oc;

                  System.out.println(oc.outerStr);


                  (я, если что, Java по сути не знаю, но ошибка не привязана к языку; простой способ понять — написать обращения к полям через this и подумать, что должно быть вместо него в данном случае)

        0
        Хорошее резюме!!! Было бы супер, внизу сделать таблицу сравнения, чтобы разница в правилах(или ее отсутствие) была видна невооруженным глазом!
          0

          Согласен, таблица будет вполне уместной. И примеры кода — как в комментариях

          +1
          Ещё не написали, что в одном файле исходного кода можно разместить множество не вложенных классов, не являющихся public, с уровнем доступа package-private (без модификатора доступа). В одном файле может содержаться только один public класс.
          После компиляции количество файлов будет равно количеству не вложенных классов.
          public class A {
          }
          class B {
          }
          class C {
          }
            0
            Я, например, стараюсь так не делать. Приходится сопровождать код с таким подходом, по 5-7 тысяч строк файлы, с множеством не вложенных классов. Это кошмар.
            +1
            Стоит упомянуть, что если Inner класс обращается к приватным полям или методам внешнего класса, компилятор генерирует synthetic accessor метод с package модификатором видимости, чтобы тот в свою очередь мог достучаться до приватного метода.

            Таким образом, если вы вызывате приватный метод внешнего класса, вы на самом деле вызываете 2 метода, accessor и тот, к которому требуется доступ.

            Сделано это потому, что в Java после компиляции нет понятия Inner класса. Inner класс всего лишь станет package классом в том же пакете, рядом с внешним классом.
              +1
              Ещё у локальных классов есть доступ к локальным effectively final переменным метода, в котором он определён.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое