Почему Android предпочитает статические классы - PullRequest
37 голосов
/ 24 июня 2010

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

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

Ответы [ 5 ]

67 голосов
/ 24 июня 2010

Это не только разработчики 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(){}
}
25 голосов
/ 24 июня 2010

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

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

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

15 голосов
/ 24 июня 2010

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

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

6 голосов
/ 24 июня 2010

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

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

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

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

Outer.Inner in = new Outer().new Inner();
5 голосов
/ 24 июня 2010

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

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

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

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

...