Внутренние и вложенные классы

144
16 декабря 2020, 14:00

Внутренние и вложенные классы — это не одно и тоже.

В чем разница, и когда принципиально нужно использовать один, а когда другой?

Answer 1

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

Но static nested классы имеют доступ к любым статическим методам внешнего класса, в том числе и к приватным.

public class Mememe {
   private static int m_AccessableInt; // доступно в StaticNestedMememe
   private int m_NotAccessableInt;     // не доступно в StaticNestedMememe
   [...]
   public static class StaticNestedMememe {
      [...]
   }
}

Применение? Например, если вложенный класс имеет смысл только в контексте обрамляющего класса.

Так же многие используют такие классы для реализации паттерна Builder.

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

Mememe.StaticNestedMememe nestedObject = new Mememe.StaticNestedMememe();

Внутренние классы бывают трёх типов:

  • локальные классы (local classes);
  • анонимные классы (anonymous classes);
  • внутренние классы-члены (member inner classes).

Локальные классы определяются внутри блока кода.

public class Mememe { 
    public void calc(String requestPath) { 
        class Сalculator{ 
             int calc() { return 0; } 
        }
    }
}

Локальные классы имеют доступ к полям и методам обрамляющего класса. Локальные классы:

  • видны только в пределах блока, в котором объявлены;
  • не могут быть объявлены как private, public, protected или static;
  • не могут иметь внутри себя статических объявлений; исключением являются константы (static final);

Анонимный класс (anonymous class) - это локальный класс без имени.

Типичный пример - реализация Runnable:

 new Thread(new Runnable() {
        public void run() {
            ...
        }
    }).start();

Основное ограничение при использовании анонимных классов - это невозможность описания конструктора, так как класс не имеет имени.

Внутренние классы-члены ассоциируются не с самим внешним классом, а с его экземпляром. При этом они имеют доступ ко всем его полям и методам. Например:

public class OuterClass { 
    public void method() { ... } 
    public class InnerClass { 
        public void method() { ... } 
        public void anotherMethod() { 
            method(); 
        } 
    } 
} 

InnerClass имеет доступ в членам класса OuterClass, как видно на примере метода anotherMethod, который вызывает метод method.

Создать такой класс можно так:

OuterClass outer = new OuterClass(); 
OuterClass.InnerClass innerClass = outer.new InnerClass(); 
Answer 2

Внутренний (inner):

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

Вложенный (nested):

  • Не требует объект родительского класса для создания
  • Не имеет доступа к приватным полям объектов родительского класса, но имеет доступ к приватным полям родительского класса.

Код:

public class Example {
    public static int si = 0;
    private static int psi = 0;
    public final Inner inner;
    public int i = 0;
    private int pi = 0;
    public Example() {
        inner = new Inner();
    }
    public static class Nested {
        int e;
        public Nested() {
            e = Example.psi;
            e = Example.si;
            // а вот так нельзя
//            e = Example.this.pi;
//            e = Example.this.i;
        }
    }
    public class Inner {
        int e;
        public Inner() {
            e = Example.psi;
            e = Example.si;
            e = Example.this.pi;
            e = Example.this.i;
        }
    }
}
class ExampleTwo {
    // Nested можно сразу
    Example.Nested nested = new Example.Nested();
    Example.Inner inner;
    {
    // так нельзя, нужен объект Example
//        inner = new Example.Inner();
        // а так можно
        Example example = new Example();
        inner = example.inner;
    }
}
READ ALSO
Почему Babel не компилирует код (Gulp + Webpack + Babel)?

Почему Babel не компилирует код (Gulp + Webpack + Babel)?

Использую связку gulp + wabpack(wabpack-stream) + babel 7

123
Не видит подключенный в main.js vue-resource

Не видит подключенный в main.js vue-resource

Я подключил в mainjs vue-resource

102
всплытие и перехват js

всплытие и перехват js

Скажите пожалуйста как сделать так, чтобы вместо eventtarget

142