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

Вы можете создать приложение с полным экраном и сделать его самым верхним окном.

Затем запустите свое приложение с окнами.

1648
задан nabster 7 January 2019 в 17:41
поделиться

9 ответов

От Учебное руководство по Java:

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

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

OuterClass.StaticNestedClass

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

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

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

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

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

Для инстанцирования внутреннего класса необходимо сначала инстанцировать внешнего класса. Затем создайте внутренний объект во внешнем объекте с этим синтаксисом:

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

см.: Учебное руководство по Java - Вложенные Классы

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

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

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

1606
ответ дан Community 7 January 2019 в 17:41
поделиться

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

Редактирование: Если Вы на самом деле имели в виду внутренний по сравнению с анонимным..., внутренний класс является просто классом, определенным в классе, таком как:

public class A {
    public class B {
    }
}

принимая во внимание, что анонимный класс является расширением класса, определенного анонимно, таким образом, никакой фактический "класс не определяется, как в:

public class A {
}

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

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

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

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

7
ответ дан user207421 7 January 2019 в 17:41
поделиться

Вложенный класс является очень общим термином: каждый класс, который не является верхним уровнем, является вложенным классом. Внутренний класс является нестатическим вложенным классом. Joseph Darcy записал очень хорошее объяснение [приблизительно 110] Вложенные, Внутренние, участник и Классы .

Верхнего уровня
8
ответ дан Bill the Lizard 7 January 2019 в 17:41
поделиться

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

Сначала разобраться в условиях:

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

Ответ Martin является правильным до сих пор. Однако фактический вопрос: Что цель объявить вложенный статичный класс или нет?

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

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

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.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. Это установлено в конструкторе, который имеет дополнительный параметр Контейнера типа для определения экземпляра включения. Вы не видите этот параметр в источнике, но компилятор неявно генерирует его для вложенного класса.

Пример Martin

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

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

new InnerClass(outerObject)

Ради полноты:

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

140
ответ дан jrudolph 7 January 2019 в 17:41
поделиться

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

public class Outer {
    public class Inner {}

    public static class Nested {}
}

Это не действительно широко принятое определение все же.

8
ответ дан Daniel Spiewak 7 January 2019 в 17:41
поделиться

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

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

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

11
ответ дан rmaruszewski 7 January 2019 в 17:41
поделиться

в учебном руководстве по Java говорится :

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

Говоря обычным языком, термины, "вложенные" и "внутренние", используются попеременно большинством программистов, но я использую правильный термин, "вложил класс", который покрывает и внутренний и статичный.

Классы могут быть вложены до бесконечности , например, класс A может содержать класс B, который содержит класс C, который содержит класс D, и т.д. Однако больше чем один уровень вложения класса редок, поскольку это - вообще плохой дизайн.

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

  • организация: иногда кажется самым разумным отсортировать класс в пространство имен другого класса, особенно когда это не будет использоваться ни в каком другом контексте
  • доступ: вложенные классы имеют специальный доступ к переменным/полям их содержания классов (точно, какие переменные/поля зависит от вида вложенного класса, или внутренний или статичный).
  • удобство: необходимость создать новый файл для каждого нового типа является надоедливой, снова, особенно когда тип будет только использоваться в одном контексте

существует четыре вида вложенного класса в Java. Короче говоря, они:

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

, Позволило мне уточнить более подробно.


Статические Классы

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

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

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

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


Внутренние Классы

внутренний класс является классом, объявленным как нестатический член другого класса:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

Как со статическим классом, внутренний класс известен, как квалифицировано его содержанием имени класса, пицца. Носорог. Коза , но в содержании класса, это может быть известно его простым именем. Однако каждый экземпляр внутреннего класса связывается с конкретным экземпляром своего содержания класса: выше, Коза созданный в [1 120] Джерри , неявно связывается с Носорог экземпляр это в [1 123] Джерри . Иначе мы делаем связанное Носорог экземпляр явный, когда мы инстанцируем Коза :

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(Замечают, Вы называете внутренний тип как всего Коза в странном новый синтаксис: Java выводит содержание типа из носорог часть. И, да новый носорог. Коза () имела бы больше смысла мне также.)

Поэтому, что это получает нас? Ну, внутренний экземпляр класса имеет доступ к членам экземпляра содержания экземпляра класса. Эти члены экземпляра включения упомянуты во внутреннем классе через [1 130] просто их простые имена, не через [1 131] это (, это во внутреннем классе относится к внутреннему экземпляру класса, не связанному, содержащему экземпляр класса):

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

Во внутреннем классе, можно обратиться к [1 134] это из содержания класса как [1 135] Rhino.this, и можно использовать это , чтобы относиться к его участникам, , например, Rhino.this.barry.


Локальные Внутренние Классы

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

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

, Если локальный внутренний класс объявляется в методе экземпляра, инстанцирование внутреннего класса связывается с экземпляром, сохраненным содержанием метода это во время создания экземпляра, и таким образом, содержание членов экземпляра класса доступно как в экземпляре внутренний класс. Локальный внутренний класс инстанцируют просто через [1 139] его имя, , например, , локальный внутренний CAT класса инстанцируют как [1 142] новый CAT () , не новый это. CAT (), как Вы могли бы ожидать.


Анонимные Внутренние Классы

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

new *ParentClassName*(*constructorArgs*) {*members*}

Это - выражение, возвращая новый экземпляр класса без имени, который расширяется ParentClassName. Вы не можете предоставить своего собственного конструктора; скорее каждый неявно предоставляется, который просто вызывает супер конструктора, таким образом, предоставленные аргументы должны соответствовать супер конструктору. (Если родитель содержит несколько конструкторов, “simplest”, которыми каждого называют, “simplest”, как определено довольно сложным рядом правил, который не стоит потрудиться учиться подробно - просто, обращают внимание на то, что NetBeans или Eclipse говорят Вам.)

, С другой стороны, можно определить интерфейс для реализации:

new *InterfaceName*() {*members*}

Такое объявление создает новый экземпляр класса без имени, который расширяет Объект и реализует InterfaceName. Снова, Вы не можете предоставить своего собственного конструктора; в этом случае Java неявно предоставляет пустого конструктора без аргументов (таким образом, никогда не будет аргументов конструктора в этом случае).

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

Быть ясным, что анонимный внутренний класс является просто менее гибким способом создать локальный внутренний класс с одним экземпляром. Если Вы хотите локальный внутренний класс, который реализует несколько интерфейсов или который реализует интерфейсы при расширении некоторого класса кроме [1 145] Объект или который определяет его собственного конструктора, Вы застреваете, создавая регулярный именованный локальный внутренний класс.

570
ответ дан informatik01 7 January 2019 в 17:41
поделиться

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

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

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

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'. настройка nested.innerItem не выполняется до тех пор, пока не будет создан экземпляр класса (или, по крайней мере, до тех пор, пока не будет сделана первая ссылка на вложенный статический элемент), как вы сами можете убедиться { {1}}, комментируя и раскомментируя строки, на которые я ссылаюсь выше. То же самое не выполняется для 'outerItem'.

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

11
ответ дан 22 November 2019 в 20:09
поделиться

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

Типы:

  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);
15
ответ дан 22 November 2019 в 20:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: