«1. Введение

Это руководство представляет собой краткое и точное введение во вложенные классы в языке Java.

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

Прежде чем мы начнем, давайте рассмотрим несколько типов вложенных классов, доступных в языке:

    Статические вложенные классы Нестатические вложенные классы Локальные классы Анонимные классы

В следующих разделах мы собираемся обсудить каждый из них подробно.

2. Статические вложенные классы

Вот несколько моментов, которые следует помнить о статических вложенных классах:

    Как и статические члены, они принадлежат охватывающему их классу, а не экземпляру класса. Они могут иметь все типы модификаторов доступа в их объявлении. У них есть доступ только к статическим членам окружающего класса. Они могут определять как статические, так и нестатические члены.

Давайте посмотрим, как мы можем объявить статический вложенный класс:

public class Enclosing {
    
    private static int x = 1;
    
    public static class StaticNested {

        private void run() {
            // method implementation
        }
    }
    
    @Test
    public void test() {
        Enclosing.StaticNested nested = new Enclosing.StaticNested();
        nested.run();
    }
}

3. Нестатические вложенные классы

Далее, вот несколько быстрых замечаний, которые следует помнить о нестатических вложенных классах:

    Их также называют внутренними классами Они могут иметь все типы модификаторов доступа в своем объявлении Так же, как переменные экземпляра и методы, внутренние классы связаны с экземпляром включающего класса. У них есть доступ ко всем членам включающего класса, независимо от того, являются ли они статическими или нестатическими. Они могут определять только нестатические члены.

Вот как мы можем объявить внутренний класс:

public class Outer {
    
    public class Inner {
        // ...
    }
}

Если мы объявим вложенный cl ass с модификатором static, то это статический член. В противном случае это внутренний класс. Несмотря на то, что синтаксически разница заключается всего в одном ключевом слове (т. е. static), семантически существует огромная разница между этими типами вложенных классов. Экземпляры внутреннего класса привязаны к экземплярам окружающего класса и поэтому имеют доступ к своим членам. Мы должны помнить об этой проблеме, когда выбираем, следует ли сделать вложенный класс внутренним.

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

Давайте посмотрим, как мы можем это сделать:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

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

3.1. Локальные классы

Локальные классы — это особый тип внутренних классов, в которых класс определяется внутри блока метода или области видимости.

Давайте рассмотрим несколько моментов, которые следует помнить об этом типе класса:

    Они не могут иметь модификаторы доступа в своем объявлении. Они имеют доступ как к статическим, так и к нестатическим членам во внешнем контексте. Они могут определять только члены-экземпляры. ~~ ~ Вот краткий пример:

3.2. Анонимные классы

public class NewEnclosing {
    
    void run() {
        class Local {

            void run() {
                // method implementation
            }
        }
        Local local = new Local();
        local.run();
    }
    
    @Test
    public void test() {
        NewEnclosing newEnclosing = new NewEnclosing();
        newEnclosing.run();
    }
}

Анонимные классы можно использовать для определения реализации интерфейса или абстрактного класса без необходимости создания повторно используемой реализации.

Давайте перечислим несколько моментов, которые следует помнить об анонимных классах:

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

    Чтобы определить анонимный класс, давайте сначала определим простой абстрактный класс:

Теперь давайте посмотрим, как мы можем определить анонимный класс :

abstract class SimpleAbstractClass {
    abstract void run();
}

Для получения более подробной информации мы можем найти полезным наше руководство по анонимным классам в Java.

public class AnonymousInnerUnitTest {
    
    @Test
    public void whenRunAnonymousClass_thenCorrect() {
        SimpleAbstractClass simpleAbstractClass = new SimpleAbstractClass() {
            void run() {
                // method implementation
            }
        };
        simpleAbstractClass.run();
    }
}

4. Затенение

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

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

Давайте рассмотрим краткий пример:

5. Сериализация

public class NewOuter {

    int a = 1;
    static int b = 2;

    public class InnerClass {
        int a = 3;
        static final int b = 4;

        public void run() {
            System.out.println("a = " + a);
            System.out.println("b = " + b);
            System.out.println("NewOuterTest.this.a = " + NewOuter.this.a);
            System.out.println("NewOuterTest.b = " + NewOuter.b);
            System.out.println("NewOuterTest.this.b = " + NewOuter.this.b);
        }
    }

    @Test
    public void test() {
        NewOuter outer = new NewOuter();
        NewOuter.InnerClass inner = outer.new InnerClass();
        inner.run();

    }
}

Чтобы избежать исключения java.io.NotSerializableException при попытке сериализации вложенного класса, мы должны:

«Объявите вложенный класс как статический. Сделайте так, чтобы и вложенный класс, и окружающий класс реализовывали Serializable

    6. Заключение

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

Как всегда, полную реализацию этого руководства можно найти на GitHub.

«