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

В чем основное различие между внутренним классом и статическим вложенным классом в Java? Влияет ли дизайн / реализация на выбор одного из них?

Ответ Джошуа Блоха находится в Эффективная Java читать item 22 : Favor static member classes over non static

Raymond Chenon 31.03.2015 13:33

Для справки, это пункт 24 в 3-м издании той же книги.

ZeroCool 08.05.2019 01:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1 853
2
775 654
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

Эммм ... внутренний класс ЯВЛЯЕТСЯ вложенным классом ... вы имеете в виду анонимный класс и внутренний класс?

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

public class A {
    public class B {
    }
}

В то время как анонимный класс является расширением класса, определенного анонимно, поэтому никакой фактический класс не определен, как в:

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

Дальнейшее редактирование:

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

Существует тонкая разница между статическим и нестатическим вложенным классом ... в основном нестатические внутренние классы имеют неявный доступ к полям экземпляра и методам включающего класса (поэтому они не могут быть созданы в статическом контексте, это будет компилятор ошибка). Статические вложенные классы, с другой стороны, не имеют неявного доступа к полям и методам экземпляра, и МОЖЕТ быть построена в статическом контексте.

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

mipadi 07.11.2008 19:05

Я думаю, что смысловая разница в основном историческая. Когда я писал компилятор C# -> Java 1.1, ссылка на язык Java была очень явной: вложенный класс статичен, внутренний класс - нет (и, следовательно, имеет этот $ 0). В любом случае это сбивает с толку, и я рад, что это больше не проблема.

Tomer Gabel 26.03.2009 16:41

JLS определяет «внутренний класс» в docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1‌ .3, и поэтому в Java невозможно иметь нестатический «внутренний класс». «Вложенный» НЕ является «просто еще одним термином, обозначающим то же самое», и НЕ ИСТИНА, что «внутренний класс - это класс, определенный внутри класса (статический или нет)». Это НЕПРАВИЛЬНАЯ информация.

Lew Bloch 02.07.2016 01:54

Эти термины взаимозаменяемы. Если вы хотите быть по-настоящему педантичным, вы определяете мог «вложенный класс» для ссылки на статический внутренний класс, который не имеет включающего экземпляра. В коде у вас может быть что-то вроде этого:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

Однако это не совсем общепринятое определение.

«статическое внутреннее» - это терминологическое противоречие.

user207421 28.11.2014 06:47

Это не соглашение, которое определяет внутренний класс как нестатический вложенный класс, а JLS. docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1‌ .3

Lew Bloch 02.07.2016 01:51

И термины нет «используются взаимозаменяемо».

user207421 20.01.2018 03:25
Ответ принят как подходящий

Из Учебник по Java:

Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are simply called static nested classes. Non-static nested classes are called inner classes.

Доступ к статическим вложенным классам осуществляется с помощью имени включающего класса:

OuterClass.StaticNestedClass

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

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

Объекты, которые являются экземплярами внутреннего класса, существуют внутри экземпляра внешнего класса. Рассмотрим следующие классы:

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

Экземпляр InnerClass может существовать только внутри экземпляра OuterClass и имеет прямой доступ к методам и полям включающего его экземпляра.

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

OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

см .: Учебник по Java - Вложенные классы

Для полноты картины отметим, что существует еще такое понятие, как внутренний класс без включающий экземпляр:

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

Здесь new A() { ... } является внутренний класс, определенный в статическом контексте и не имеет включающего экземпляра.

Помните, что вы также можете напрямую импортировать статический вложенный класс, то есть вы можете сделать (вверху файла): import OuterClass.StaticNestedClass;, а затем ссылаться на класс только как на OuterClass.

Camilo Díaz Repka 16.07.2011 04:22

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

Экземпляр внутреннего класса создается при создании экземпляра внешнего класса. Следовательно, члены и методы внутреннего класса имеют доступ к членам и методам экземпляра (объекта) внешнего класса. Когда экземпляр внешнего класса выходит за пределы области видимости, экземпляры внутреннего класса также перестают существовать.

Статический вложенный класс не имеет конкретного экземпляра. Он просто загружается при первом использовании (как и статические методы). Это полностью независимая сущность, методы и переменные которой не имеют доступа к экземплярам внешнего класса.

Статические вложенные классы не связаны с внешним объектом, они быстрее и не занимают память кучи / стека, потому что нет необходимости создавать экземпляр такого класса. Поэтому практическое правило - попытаться определить статический вложенный класс с максимально ограниченной областью действия (private> = class> = protected> = public), а затем преобразовать его во внутренний класс (удалив «статический» идентификатор) и ослабить размах, если это действительно необходимо.

Первое предложение неверно. Не существует такой вещи, как «экземпляр в внутреннего класса», и его экземпляры могут быть созданы в любое время после создания экземпляра внешнего класса. Второе предложение не следует из первого предложения.

user207421 11.05.2015 02:55

Я не думаю, что настоящая разница проявилась в приведенных выше ответах.

Прежде всего, чтобы понять условия:

  • Вложенный класс - это класс, который содержится в другом классе на уровне исходного кода.
  • Он статичен, если вы объявляете его с модификатором статический.
  • Нестатический вложенный класс называется внутренним классом. (Я остаюсь с нестатическим вложенным классом.)

Ответ Мартина пока верен. Однако на самом деле возникает вопрос: какова цель объявления вложенного класса статическим или нет?

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

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

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

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

Далее следуют более хардкорные объяснения:

Если вы посмотрите на байт-коды Java, которые компилятор генерирует для (нестатического) вложенного класса, это может стать еще яснее:

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

Как видите, компилятор создает скрытое поле Container this$0. Это устанавливается в конструкторе, который имеет дополнительный параметр типа Container для указания включающего экземпляра. Вы не можете увидеть этот параметр в источнике, но компилятор неявно генерирует его для вложенного класса.

Пример Мартина

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

был бы скомпилирован для вызова чего-то вроде (в байт-кодах)

new InnerClass(outerObject)

Для полноты:

Анонимный класс является - прекрасный пример нестатического вложенного класса, который просто не имеет связанного с ним имени и на который нельзя ссылаться позже.

«Нет семантической разницы между статическим вложенным классом и любым другим классом». За исключением того, что вложенный класс может видеть частные поля / методы родителя, а родительский класс может видеть частные поля / методы вложенных.

Brad Cupit 22.06.2010 18:56

Разве нестатический внутренний класс не вызовет массовые утечки памяти? Например, каждый раз, когда вы создаете слушателя, вы создаете утечку?

G_V 15.12.2014 11:24

@G_V определенно существует вероятность утечки памяти, потому что экземпляр внутреннего класса хранит ссылку на внешний класс. Является ли это актуальной проблемой, зависит от того, где и как хранятся ссылки на экземпляры внешнего и внутреннего классов.

jrudolph 17.12.2014 12:09

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

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

Рассмотрим этот пример:

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

Хотя и nested, и innerItem объявлены как static final. Настройки of nested.innerItem не происходит до тех пор, пока не будет создан экземпляр класса (или, по крайней мере, только после первого обращения к вложенному статическому элементу), как вы сами можете убедиться комментируя и раскомментируя строки, на которые я ссылаюсь выше. То же самое не выполняется верно для 'outerItem'.

По крайней мере, это то, что я вижу в Java 6.0.

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

Типы:

  1. Статический вложенный класс
  2. Нестатический вложенный класс [Внутренний класс]

Разница:

Нестатический вложенный класс [Внутренний класс]

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

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

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

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

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

Если вы хотите получить доступ к x, напишите следующий внутренний метод

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

Я думаю, что обычно соблюдаются следующие правила:

  • статический класс в классе верхнего уровня - это вложенный класс
  • нестатический класс внутри класса верхнего уровня является внутренний класс, который дополнительно имеет еще две формы:
    • местный класс - именованные классы, объявленные внутри блока, такие как тело метода или конструктора
    • анонимный класс - безымянные классы, экземпляры которых создаются в выражениях и операторах

Однако несколько других указывает на запоминание:

  • Классы верхнего уровня и статический вложенный класс семантически одинаковы, за исключением того, что в случае статического вложенного класса он может делать статические ссылки на частные статические поля / методы своего внешнего [родительского] класса и наоборот.

  • Внутренние классы имеют доступ к переменным экземпляра включающего экземпляра класса Outer [parent]. Однако не все внутренние классы имеют включающие экземпляры, например внутренние классы в статических контекстах, такие как анонимный класс, используемый в блоке статического инициализатора, не имеют.

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

    • new YourClass(){}; означает class [Anonymous] extends YourClass {}
    • new YourInterface(){}; означает class [Anonymous] implements YourInterface {}

Я чувствую, что остается открытым более серьезный вопрос, какой из них использовать и когда? Ну, это в основном зависит от того, с каким сценарием вы имеете дело, но чтение ответа @jrudolph может помочь вам принять какое-то решение.

Я думаю, что люди здесь должны обратить внимание на Poster, что: Static Nest Class - это только первый внутренний класс. Например:

 public static class A {} //ERROR

 public class A {
     public class B {
         public static class C {} //ERROR
     }
 }

 public class A {
     public static class B {} //COMPILE !!!

 }

Итак, резюмируя, статический класс не зависит, какой класс он содержит. Значит, в нормальном классе они не могут. (потому что нормальному классу нужен экземпляр).

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

user207421 24.03.2016 07:06

Я думаю, что ни один из приведенных выше ответов не объясняет вам реальную разницу между вложенным классом и статическим вложенным классом с точки зрения дизайна приложения:

OverView

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

Разница

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

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

Вывод

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

: из вашего вывода "пока статические не могут", ни даже статические экземпляры контейнера? Конечно?

Vedant Kekan 21.07.2015 12:39

Обычно статический вложенный класс используется в шаблоне проектирования ViewHolder в RecyclerView и ListView.

Hamzeh Soboh 18.08.2015 12:21

Во многих случаях краткий ответ яснее и лучше. Вот такой пример.

user218867 09.01.2017 20:38

Статический вложенный класс может получить доступ к статическим полям включающего класса.

Artiom Lemiasheuski 06.07.2020 15:14

Прежде всего, нет такого класса, называемого статическим классом. Использование статического модификатора с внутренним классом (называемым вложенным классом) говорит о том, что это статический член внешнего класса, что означает, что мы можем получить к нему доступ, как и к другим статическим членам, и без каких-либо экземпляр внешнего класса. (Что изначально является преимуществом статики.)

Разница между использованием вложенного класса и обычного внутреннего класса:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

Сначала мы можем создать экземпляр Outerclass, а затем получить доступ к Inner.

Но если класс вложен, то синтаксис следующий:

OuterClass.InnerClass inner = new OuterClass.InnerClass();

В котором статический синтаксис используется как обычная реализация ключевого слова static.

«... говорит, что это статический член внешнего класса, что означает ....»: не неправильно думать о статическом вложенном классе как о «классе-члене» внешнего класса, но сходство со статическими полями и методы на этом заканчиваются. Статический вложенный класс не «принадлежит» внешнему классу. Практически во всех случаях, когда это имеет значение, статический вложенный класс - это отдельно стоящий класс верхнего уровня, определение класса которого было вложено внутри определения внешнего класса для удобства упаковки (и, надеюсь, потому что существует логическая связь между вложенным классом и внешним классом. ... хотя и не обязательно).

scottb 18.10.2013 04:03

«статическое внутреннее» - это терминологическое противоречие. Статические классы действительно существуют на первом уровне вложенности и по определению не являются внутренними классами. Очень смущенный.

user207421 28.11.2014 06:50

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

Вложенные классы - это классы, определенные внутри тела другого включающего класса. Они бывают двух типов - статические и нестатические.

Они рассматриваются как члены включающего класса, поэтому вы можете указать любой из четырех спецификаторов доступа - private, package, protected, public. У нас нет этой роскоши с классами верхнего уровня, которые можно объявить только public или package-private.

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

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1 - это наш статический внутренний класс, а Inner2 - наш внутренний класс, который не является статическим. Ключевое различие между ними в том, что вы не можете создать экземпляр Inner2 без внешнего, тогда как вы можете создать объект Inner1 независимо.

Когда бы вы использовали внутренний класс?

Подумайте о ситуации, когда Class A и Class B связаны, Class B должен иметь доступ к членам Class A, а Class B связан только с Class A. На сцену выходят внутренние классы.

Для создания экземпляра внутреннего класса вам необходимо создать экземпляр вашего внешнего класса.

OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

или же

OuterClass.Inner2 inner = new OuterClass().new Inner2();

Когда бы вы использовали статический внутренний класс?

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

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

OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

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

ты имел ввиду OuterClass.Inner2 inner = outer.new Inner2();?

Erik Kaplun 12.03.2014 06:57

static inner - противоречие в терминах.

user207421 06.06.2016 09:30

А внутренние классы также не называются «классами, не относящимися к стеку». Не используйте форматирование кода для текста, который не является кодом, и используйте его для текста, который есть.

user207421 02.01.2017 08:16

В случае создания экземпляра экземпляр non статический внутренний класс создается со ссылкой на объект внешнего класса, в котором он определен. Этот означает, что у него есть закрывающий экземпляр. Но экземпляр статического внутреннего класса создается со ссылкой на внешний класс, а не с ссылка на объект внешнего класса. Это значит это не имеет закрывающего экземпляра.

Например:

class A
{
  class B
  {
    // static int x; not allowed here…..    
  }
  static class C
  {
    static int x; // allowed here
  }
}

class Test
{
  public static void main(String… str)
  {
    A o=new A();
    A.B obj1 =o.new B();//need of inclosing instance

    A.C obj2 =new A.C();

    // not need of reference of object of outer class….
  }
}

«статическое внутреннее» - это терминологическое противоречие. Вложенный класс бывает статическим или внутренним.

user207421 11.05.2015 02:58

Ориентация на учащихся, которые не знакомы с Java и / или вложенными классами

Вложенные классы могут быть:
1. Статические вложенные классы. 2. Нестатические вложенные классы. (также известный как Внутренние классы) => Пожалуйста, запомните это


1. внутренние классы
Пример:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


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

  • внутренний класс - это особый тип вложенного класса
  • внутренние классы - это подмножества вложенных классов
  • Можно сказать, что внутренний класс также является вложенным классом, но вы можете НЕТ сказать, что вложенный класс также является внутренним классом.

Специальность Внутреннего класса:

  • экземпляр внутреннего класса имеет доступ ко всем членов внешнего класса, даже тех, которые помечены как «частные»


2. статические вложенные классы:
Пример:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

Случай 1. Создание статического вложенного класса из не включающего класса

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

Случай 2: создание статического вложенного класса из включающего класса

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

Специальность статических классов:

  • Статический внутренний класс будет иметь доступ только к статическим членам внешнего класса и не будет иметь доступа к нестатическим членам.

Вывод:
Вопрос: В чем основное различие между внутренним классом и статическим вложенным классом в Java?
Отвечать: просто рассмотрим особенности каждого класса, упомянутого выше.

Я не думаю, что здесь есть что добавить, большинство ответов прекрасно объясняют различия между статическим вложенным классом и внутренними классами. Однако при использовании вложенных классов по сравнению с внутренними классами следует учитывать следующую проблему. Как упоминалось в нескольких ответах, внутренние классы не могут быть созданы без и экземпляра их включающего класса, что означает, что они ДЕРЖАТЬ a указатель к экземпляру их включающего класса, что может привести к переполнению памяти или исключению переполнения стека из-за того, что GC не сможет собирать мусор включающие классы, даже если они больше не используются. Чтобы прояснить это, проверьте следующий код:

public class Outer {


    public  class Inner {

    }


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

    @Override
    protected void finalize() throws Throwable {
    // as you know finalize is called by the garbage collector due to destroying an object instance
        System.out.println("I am destroyed !");
    }
}


public static void main(String arg[]) {

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

    // out instance is no more used and should be garbage collected !!!
    // However this will not happen as inner instance is still alive i.e used, not null !
    // and outer will be kept in memory until inner is destroyed
    outer = null;

    //
    // inner = null;

    //kick out garbage collector
    System.gc();

}

Если убрать комментарий к // inner = null; Программа выдаст "Я уничтожен!", но оставляя это в комментариях, этого не произойдет. Причина в том, что на белый внутренний экземпляр все еще ссылаются, GC не может его собрать, и поскольку он ссылается (имеет указатель) на внешний экземпляр, он тоже не собирается. Наличие достаточного количества этих объектов в вашем проекте может привести к нехватке памяти. По сравнению со статическими внутренними классами, которые не содержат точки для экземпляра внутреннего класса, потому что он связан не с экземпляром, а с классом. Вышеупомянутая программа может напечатать "Я уничтожен!", если вы сделаете внутренний класс статическим и создадите его экземпляр с помощью Outer.Inner i = new Outer.Inner();.

Вот основные различия и сходства между внутренним классом Java и статическим вложенным классом.

Надеюсь, это поможет!

Внутренний класс

  • Может получить доступ для методов и полей внешнего класса как экземпляр, так и статический
  • Связан с экземпляром включающего класса, поэтому для его создания сначала требуется экземпляр внешнего класса (обратите внимание на место ключевого слова новый):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
    
  • Не можешь определяет любой сам статические члены

  • Не можешь имеет декларацию Учебный класс или Интерфейс

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

  • Нет доступа методы или поля внешнего класса пример

  • Не связан ни с одним экземпляром включающего класса Итак, чтобы создать его экземпляр:

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
    

Сходства

  • Оба Внутренние классы могут получить доступ даже к частные поля и методы из внешний класс
  • Также Внешний класс имеет доступ к частные поля и методы из внутренние классы
  • Оба класса могут иметь модификатор доступа private, protected или public.

Зачем использовать вложенные классы?

Согласно документации Oracle есть несколько причин (полная документация):

  • It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.

  • It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.

  • It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.

Я не думаю, что это совсем верно. Внутренний класс может иметь внутри другой внутренний класс.

Scratte 31.01.2021 08:31

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

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

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

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

user207421 25.06.2017 15:58

@ user207421 Что это за синтаксис? Вы имеете в виду new outer().new inner()?

Scratte 31.01.2021 11:44

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

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

Когда мы объявляем нестатический класс-член внутри класса, он называется внутренним классом. Внутренний класс можно продемонстрировать, как показано ниже:

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}
«Когда мы объявляем статический класс-член внутри класса, он называется вложенным классом верхнего уровня» That doesn't make sense. «класс высшего уровня - это класс, который не является вложенным классом». There's no such thing as a "top level nested class".
Radiodef 08.08.2018 05:36

Ниже приведен пример static nested class и inner class:

OuterClass.java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

OuterClassTest:

public class OuterClassTest {
    public static void main(String[] args) {

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}

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

Что такое внутренний класс в Java?

Любой класс, который не является верхним уровнем или объявлен внутри другого класса, называется вложенным классом, а вне этих вложенных классов класс, который объявлен нестатическим, известен как внутренний класс в Java. В Java есть три вида внутренних классов:

1) Локальный внутренний класс - объявляется внутри блока кода или метода. 2) Анонимный внутренний класс - это класс, который не имеет имени для ссылки и инициализируется в том же месте, где он создается. 3) Внутренний класс-член - объявлен как нестатический член внешнего класса.

public class InnerClassTest {
    public static void main(String args[]) {      
        //creating local inner class inside method i.e. main() 
        class Local {
            public void name() {
                System.out.println("Example of Local class in Java");

            }
        }      
        //creating instance of local inner class
        Local local = new Local();
        local.name(); //calling method from local inner class

        //Creating anonymous inner class in Java for implementing thread
        Thread anonymous = new Thread(){
            @Override
            public void run(){
                System.out.println("Anonymous class example in java");
            }
        };
        anonymous.start();

        //example of creating instance of inner class
        InnerClassTest test = new InnerClassTest();
        InnerClassTest.Inner inner = test.new Inner();
        inner.name(); //calling method of inner class
    }

     //Creating Inner class in Java
    private class Inner{
        public void name(){
            System.out.println("Inner class example in java");
        }
    }
}

Что такое вложенный статический класс в Java?

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

1) Он может получить доступ к статические элементы данных внешнего класса, включая частный. 2) Статический вложенный класс не может получить доступ к нестатический (экземплярный) элемент данных или метод.

public class NestedStaticExample {
    public static void main(String args[]){  
        StaticNested nested = new StaticNested();
        nested.name();
    }  
    //static nested class in java
    private static class StaticNested{
        public void name(){
            System.out.println("static nested class example in java");
        }
    }
}

Ссылка: Внутренний класс и вложенный статический класс в Java с примером

«Статический вложенный класс не может получить доступ к нестатическому (экземпляру) элементу данных или методу». is incorrect, and вызывая путаницу. They absolutely do have access to private instance information -- provided they create an instance to access that instance information on. They don't have an enclosing instance like inner classes do, but they do have access to their enclosing class's instance private members.
T.J. Crowder 11.04.2017 13:23

Я проиллюстрировал различные возможные правильные сценарии и сценарии ошибок, которые могут возникнуть в java-коде.

    class Outter1 {

        String OutStr;

        Outter1(String str) {
            OutStr = str;
        }

        public void NonStaticMethod(String st)  {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            //  below static attribute not permitted
            // static String tempStatic1 = "static";    

            //  below static with final attribute not permitted         
            // static final String  tempStatic1 = "ashish";  

            // synchronized keyword is not permitted below          
            class localInnerNonStatic1 {            

                synchronized    public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /* 
        //  static method with final not permitted
          public static void innerStaticMethod(String str11) { 

                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }                            

        }

        public static  void StaticMethod(String st)     {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            // static attribute not permitted below
            //static String tempStatic1 = "static";     

            //  static with final attribute not permitted below
            // static final String  tempStatic1 = "ashish";                         

            class localInnerNonStatic1 {
                public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /*
    // static method with final not permitted
    public static void innerStaticMethod(String str11) {  
                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }    

        }

        // synchronized keyword is not permitted
        static  class inner1 {          

            static String  temp1 = "ashish";
            String  tempNonStatic = "ashish";
            // class localInner1 {

            public void innerMethod(String str11) {
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            public static void innerStaticMethod(String str11) {
                //  error in below step
                str11 = temp1 +" india";    
                //str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }
            //}
        }

        //synchronized keyword is not permitted below
        class innerNonStatic1 {             

//This is important we have to keep final with static modifier in non
// static innerclass below
            static final String  temp1 = "ashish";  
            String  tempNonStatic = "ashish";
            // class localInner1 {

            synchronized    public void innerMethod(String str11) {
                tempNonStatic = tempNonStatic +" ...";
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            /*
            //  error in below step
            public static void innerStaticMethod(String str11) {   
                            //  error in below step
                            // str11 = tempNonStatic +" india";                     
                            str11 = temp1 +" india";
                            System.out.println("innerMethod ===> "+str11);
                        }*/
                    //}
                }
    }

Очевидно кодовая часть. И если вы не заметили: ваш пример кода очень трудно читать. Даже на моем огромном настольном мониторе у меня есть горизонтальная полоса прокрутки. Попробуйте разместить свои комментарии выше или ниже того, что они комментируют, вместо позади.

GhostCat 11.10.2017 09:12

Не уверен, что понимаю ваше использование слова «синхронизировано». Когда это можно, а когда нельзя и почему? У вас есть комментарии, противоречащие тому, что показывает код.

Scratte 31.01.2021 11:40

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

class OuterClass {
...
class NestedClass {
    ...
    }
}

Вложенные классы делятся на две категории: статические и нестатические. Вложенные классы, объявленные статическими, называются статическими вложенными классами. Нестатические вложенные классы называются внутренними классами. Следует иметь в виду, что нестатические вложенные классы (внутренние классы) имеют доступ к другим членам включающего класса, даже если они объявлены закрытыми. Статические вложенные классы имеют доступ только к другим членам включающего класса, если они статические. Он не может получить доступ к нестатическим членам внешнего класса. Как и в случае с методами и переменными класса, статический вложенный класс связан со своим внешним классом. Например, чтобы создать объект для статического вложенного класса, используйте этот синтаксис:

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass(); 

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

OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

Почему мы используем вложенные классы

  1. Это способ логической группировки классов, которые используются только в одном месте.
  2. Это увеличивает инкапсуляцию.
  3. Это может привести к созданию более читаемого и поддерживаемого кода.

Источник: Учебники по Java ™ - Вложенные классы

Я думаю, что ни один из приведенных выше ответов не дает вам реального примера разницы между вложенным классом и статическим вложенным классом с точки зрения дизайна приложения. И главное различие между статическим вложенным классом и внутренним классом - это возможность доступа к полю экземпляра внешнего класса.

Давайте посмотрим на два следующих примера.

Статический вложенный класс: хорошим примером использования статических вложенных классов является шаблон построителя (https://dzone.com/articles/design-patterns-the-builder-pattern).

Для BankAccount мы используем статический вложенный класс, главным образом потому, что

  1. Экземпляр статического вложенного класса может быть создан до внешнего класса.

  2. В шаблоне построителя построитель - это вспомогательный класс, который используется для создания BankAccount.

  3. BankAccount.Builder связан только с BankAccount. Никакие другие классы не связаны с BankAccount.Builder. поэтому лучше организовать их вместе, не используя соглашения об именах.
public class BankAccount {

    private long accountNumber;
    private String owner;
    ...

    public static class Builder {

    private long accountNumber;
    private String owner;
    ...

    static public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Builder withOwner(String owner){
        this.owner = owner;
        return this; 
    }

    ...
    public BankAccount build(){
            BankAccount account = new BankAccount(); 
            account.accountNumber = this.accountNumber;
            account.owner = this.owner;
            ...
            return account;
        }
    }
}

Внутренний класс. Обычно внутренние классы используются для определения обработчика событий. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

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

  1. Внутреннему классу MyAdapter требуется доступ к внешнему члену класса.

  2. В этом примере MyAdapter связан только с MyClass. Никакие другие классы не связаны с MyAdapter. поэтому лучше организовать их вместе без использования соглашения об именах

public class MyClass extends Applet {
    ...
        someObject.addMouseListener(new MyAdapter());
    ...
    class MyAdapter extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            ...// Event listener implementation goes here...
            ...// change some outer class instance property depend on the event
        }
    }
}

Диаграмма

Основное различие между классами static nested и non-static nested заключается в том, что static nestedне имеет - это доступ к нестатическим внешним членам класса.

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