Статический вложенный класс в Java, почему?


Я смотрел на Java-код для LinkedList и заметил, что он использовал статический вложенный класс, Entry.

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

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

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

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

Примечание. Я надеюсь, что мои термины верны, я бы назвал это статическим внутренним классом, но я думаю, что это неправильно:http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html

13 184

13 ответов:

страница Sun, на которую вы ссылаетесь, имеет некоторые ключевые различия между ними:

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

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

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

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

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

имейте в виду, что я предвзят, поскольку c# fan - C# не имеет эквивалента внутренних классов, хотя у него есть вложенные типы. Я не могу сказать, что я пропустил внутренние классы еще:)

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

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

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

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

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

пример для такого рода использования, вы можете найти в Android R.java (ресурсы) файл. Папка Res android содержит макеты (содержащие дизайн экрана), рисованная папка (содержит изображения, используемые для проекта), папка значений (которая содержит строковые константы) и т. д..

синус все папки являются частью папки Res, инструмент android генерирует R.java (ресурсы) файл, который внутренне содержит много статических вложенных классов для каждой из своих внутренних папок.

вот внешний вид R.java файл, созданный в android: Здесь их используют только для удобства упаковки.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}

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

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

это выведет x: 1

простой пример :

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

Если нестатический класс не может быть создан exept в экземпляре верхнего класса (поэтому не в Примере, где main является статической функцией)

от http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html:

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

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

PS: Я всегда понимал, что "вложенные" и "внутренние" взаимозаменяемы. Там могут быть тонкие нюансы в терминах, но большинство разработчиков Java будет понимать либо.

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

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

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

тут static гарантирует, что класс Student имеет только один компаратор, а не создает новый экземпляр каждый раз, когда создается новый экземпляр student.

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

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

Adavantage внутреннего класса--

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

без существования внешнего класса внутренний класс не будет существовать.

class car{
    class wheel{

    }
}

есть четыре типа внутреннего класса.

  1. обычный внутренний класс
  2. метод локальный внутренний класс
  3. анонимный внутренний класс
  4. статический внутренний класс

точка ---

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

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  4. inorder, чтобы вызвать обычный внутренний класс в районе экземпляр космического класс.

    Inner i=new Inner();

  5. для того, чтобы вызвать нормальный внутренний класс во внешнем классе.

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  6. внутри внутреннего класса этот указатель на внутренний класс.

    this.member-current inner class outerclassname.this--outer class

  7. для внутреннего класса применимым модификатором является -- public, default,

    final,abstract,strictfp,+private,protected,static

  8. outer$inner-это имя внутреннего класса имя.

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

10.внутреннего класса внутри статического метода, то мы можем получить доступ только к статическим полем

внешний класс.

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}