Почему Android предпочитает статические классы

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

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

38
задан Jeremy Edwards 24 June 2010 в 02:42
поделиться

5 ответов

Это не только разработчики 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(){}
}
68
ответ дан 27 November 2019 в 03:06
поделиться

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

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

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

25
ответ дан 27 November 2019 в 03:06
поделиться

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

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

15
ответ дан 27 November 2019 в 03:06
поделиться

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

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

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();
7
ответ дан 27 November 2019 в 03:06
поделиться

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

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

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

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

5
ответ дан 27 November 2019 в 03:06
поделиться
Другие вопросы по тегам:

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