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

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

1. Вступление

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

Проще говоря, Java позволяет нам определять классы внутри других классов. Nested classes enable us to logically group classes that are only used in one place, write more readable and maintainable code and increase encapsulation.с

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

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

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

  • Местные занятия

  • Анонимные занятия

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

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 {
        // ...
    }
}

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

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

Посмотрим, как мы можем это сделать:

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

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

3.1. Местные классы

Локальные классы - это особый тип внутренних классов, в которомthe class is defined inside a method или блок области видимости.

Давайте посмотрим, что нужно помнить об этом типе занятий:

  • Они не могут иметь модификаторы доступа в своем объявлении

  • Они имеют доступ как к статическим, так и к нестатическим элементам в окружающем контексте.

  • Они могут определять только элементы экземпляра.

Вот быстрый пример:

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

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

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

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

  • Они не могут иметь модификаторы доступа в своем объявлении

  • Они имеют доступ как к статическим, так и к нестатическим элементам в окружающем контексте.

  • Они могут определять только элементы экземпляра.

  • Это единственный тип вложенных классов, который не может определять конструкторы или расширять / реализовывать другие классы или интерфейсы.

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

abstract class SimpleAbstractClass {
    abstract void run();
}

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

public class AnonymousInnerTest {

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

Для получения дополнительных сведений мы можем найти полезным наш учебник поAnonymous Classes in Java.

4. Слежка

The declaration of the members of an inner class shadow those of the enclosing class, если у них одинаковое имя.

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

Давайте посмотрим на быстрый пример:

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

    }
}

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

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

  • Объявите вложенный класс какstatic

  • Сделайте как вложенный класс, так и включающий класс реализациейSerializable

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

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

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