2010-06-24 4 views
37

Я вижу много Java-кода, где андроид предпочитает, чтобы разработчики использовали статические внутренние классы. Особенно для шаблонов, таких как ViewHolder Pattern в пользовательских списках.Почему Android предпочитает статические классы

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

ответ

62

Это не только Android разработчики ...

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

class Outer { 
    class NonStaticInner {} 
    static class StaticInner {} 
    public List<Object> foo(){ 
     return Arrays.asList(
      new NonStaticInner(), 
      new StaticInner()); 
    } 
} 

Когда вы скомпилировать его, что вы получите, будет что-то вроде этого:

class Outer { 
    Outer(){} 
    public List<Object> foo(){ 
     return Arrays.asList(
      new Outer$NonStaticInner(this), 
      new StaticInner()); 
    } 
} 
class Outer$NonStaticInner { 
    private final Outer this$0; 
    Outer$NonStaticInner(Outer enclosing) { this$0 = enclosing; } 
} 
class Outer$StaticInner { 
    Outer$StaticInner(){} 
} 
+2

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

+4

+1 для впечатления, что компилятор сделает из источника ввода – Seven

+0

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

14

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

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

+0

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

24

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

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

Как это влияет на память и/или производительность? Я действительно не знаю. :)

+2

«Как это влияет на память и/или производительность?» Это предотвратит утечку памяти. Наличие статического внутреннего класса не позволяет ему ссылаться на Activity/Fragment, так как статический внутренний класс не может получить доступ к внешней переменной-члену. Если у нас есть утечка памяти в Activity, и эта активность сохраняет ссылку на многие тяжелые объекты (например, Views), она будет потреблять ненужную память и замедлять производительность. – aldok

4

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

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

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

В случае реализации классов UI, таких как swing или android, вы увидите статические внутренние классы, потому что они рассматриваются как частные функции. Эти классы не разработаны для повторного использования вне внешнего класса и сильно связаны с внутренней реализацией внешнего класса. Нет причин раскрывать их и следить за тем, чтобы они могли работать в большем количестве случаев, чем конкретный контекст требований внешнего класса.

4

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

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

class Outer{ 
    class Inner{//Only works with non static inner class 
      public Outer getOuter(){return Outer.this;} 
    } 
} 

Уместно также для ее использования, ссылка на внешний класс является т х р аргумента внутреннего класса, чтобы создать новый неофициальный статический объект внутреннего класса вы должны вызвать CTOR вроде memberfunction на экземпляр внешнего класса или изнутри функции-члена внешнего класса. Это означает, что вы не можете иметь экземпляр внутреннего класса без экземпляра внешнего класса.

Outer.Inner in = new Outer().new Inner(); 
Смежные вопросы