Если вы декомпилируете внутренний класс (или просмотрите его с помощью отладчика), вы увидите, что существует сгенерированный код для доступа к экземпляру внешнего класса, который использовался для их создания. Затраты на это - больше памяти для дополнительного указателя, больше процессора для сборки мусора из-за дополнительного указателя для тестирования, и, если вы не хотите выбирать, больше времени компиляции. Создание экземпляров нестатических внутренних классов немного сложнее, потому что для их создания вам необходим экземпляр внешнего класса.
Можно контролировать видимость как статических, так и нестатических внутренних классов. Обычно они являются закрытыми, если их реализация тесно связана с внутренними деталями внешнего класса, и разработчик не считает, что код можно использовать повторно. В этом смысле они не лучше частных функций. Внутренние классы могут быть открытыми в таких случаях, как Map.Entry, где внутренний класс тесно связан с интерфейсом, предоставляемым классом, и разработчик не считает, что Map.Entry можно использовать без какой-либо карты. Оба типа имеют доступ к закрытым членам внешнего класса, а внешний класс имеет доступ к закрытым членам внутреннего класса.
Экземпляры статических и нестатических внутренних классов собираются как мусор, как и любой другой класс. Не существует особой связи между сборкой мусора внешнего класса и сборкой мусора внутреннего класса.
В случае реализации классов UI, таких как Swing или Android, вы увидите статические внутренние классы, потому что они обрабатываются как закрытая функция. Эти классы не разработаны для повторного использования вне внешнего класса и тесно связаны с внутренней реализацией внешнего класса. Нет причин выставлять их и убедиться, что они могут работать в большем количестве случаев, чем конкретный контекст требований внешнего класса.