Есть ли накладные расходы на производительность частного внутреннего класса в Java?

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

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

Но как насчет видимости самого класса? Есть накладные расходы на

 private static class A {
      A(){}
 }

против

 static class A {
      A(){}
 }

Обратите внимание, что конструктор защищен пакетом в обоих случаях, или изменение класса private?


person Thilo    schedule 10.02.2011    source источник
comment
возможный дубликат Легковесны ли внутренние классы?   -  person templatetypedef    schedule 10.02.2011
comment
Интересно, используется ли Hotspot каким-либо образом уменьшенная видимость? Также мне интересно, могут ли компиляторы Java использовать этот факт, чтобы исключить класс из рассмотрения за пределами его видимости. Интересный вопрос, но не думаю, что в этом есть практическая польза.   -  person Ron    schedule 10.02.2011
comment
@Ron: Компилятор / IDE обязательно проверит видимость и сделает ошибки компиляции или удалит их из автозаполнения. Мне просто интересно, происходит ли что-нибудь во время выполнения.   -  person Thilo    schedule 10.02.2011
comment
Да, я имел ввиду более быструю компиляцию и генерацию автозаполнения   -  person Ron    schedule 10.02.2011


Ответы (3)


Вы пробовали скомпилировать его и сравнить байт-код? Вот мои результаты. За:

public class Example {
  public static void main(String[] args) {
    System.out.println("Hello world!");
  }
  private static class A {
    A(){}
  }
}

Приведенное выше дает следующие файлы * .class:

-rw-r--r--    1 michaelsafyan  staff   238 Feb 10 00:11 Example$A.class
-rw-r--r--    1 michaelsafyan  staff   474 Feb 10 00:11 Example.class

Теперь, если я перемещаю файлы классов, удаляю модификатор private и перекомпилирую, я получаю:

 -rw-r--r--    1 michaelsafyan  staff   238 Feb 10 00:15 Example$A.class
 -rw-r--r--    1 michaelsafyan  staff   474 Feb 10 00:15 Example.class

Если вы посмотрите спецификацию ВМ для файлов классов, вы увидите, что существует битовое поле постоянного размера для указания модификаторов доступа, поэтому неудивительно, что сгенерированные файлы имеют одинаковый размер.

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

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

person Michael Aaron Safyan    schedule 10.02.2011
comment
@Thilo, это потому, что вы ни на что не ссылаетесь во внешнем классе; если вам нужно получить доступ к членам или функциям внешнего класса, тогда будет законная причина сделать его нестатическим. - person Michael Aaron Safyan; 10.02.2011

Не должно быть разницы в производительности между частным внутренним классом и частным внутренним классом.

Не должно быть разницы в производительности между статическим внутренним классом (частным или нет) и внешним классом.

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

person Stephen C    schedule 10.02.2011
comment
И (чтобы охватить все случаи) также есть небольшая разница в производительности при обходе частной видимости (полей, методов и конструкторов) с внутренними классами. - person Thilo; 10.02.2011
comment
@Thilo - Есть? Почему? AFAIK, правила видимости применяются компилятором и верификатором. К тому времени, когда вы сможете выполнить (или JIT-компиляцию) байт-коды, все проверки видимости будут выполнены, и это не повлияет на производительность. - person Stephen C; 10.02.2011
comment
Разница в производительности возникает из-за доступа к частному методу через созданный компилятором синтетический метод оболочки, а не за прямой доступ к методу, защищенному пакетом. - person Thilo; 10.02.2011
comment
@ Тило ... гм ... Понятно. Хотя я ожидаю, что JIT-компилятор встроит вызов. - person Stephen C; 10.02.2011

Маловероятно, что это когда-либо вызовет значительное замедление.

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

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

Это не относится к статическим внутренним классам!

Делать все поля защищенными для предотвращения синтетических методов не рекомендуется. Вы отказываетесь от инкапсуляции, которая очень ценна. Что вас беспокоит? Размер ваших файлов классов для дополнительного кода?

person Jochen Bedersdorfer    schedule 10.02.2011
comment
Инкапсуляция наиболее важна на уровне пакета, поэтому я не собираюсь отказываться от этого. Внешние пакеты (то есть чужой код) не могут видеть класс в любом случае. - person Thilo; 10.02.2011
comment
@Thilo Просто потому, что это так прямо сейчас, это не обязательно означает, что так будет всегда. Инкапсуляция готовит вас больше к незапланированному, чем к ожидаемому. - person TheBlastOne; 10.02.2011
comment
@TheBlastOne: Опять же, я здесь вообще не нарушаю инкапсуляцию. Все по-прежнему является частным пакетом. - person Thilo; 10.02.2011
comment
Инкапсуляция наиболее важна на уровне пакета. На уровне пакета инкапсуляции нет. Если вы сделаете свои поля незащищенными, ваш класс потеряет контроль над тем, что в них находится. После этого ваши объекты могут войти в недопустимое состояние в любое время. - person Jochen Bedersdorfer; 10.02.2011
comment
Если внешний класс содержит значительный объем данных, это может снизить производительность приложения. stackoverflow.com/a/8257808/521754 - person despot; 02.05.2012
comment
Я не вижу соответствующей информации, подтверждающей это утверждение. Я предполагаю, что автор имел в виду, что утечка значительного объема памяти через нестатические классы может замедлить сборку мусора. Ага. Возможно. - person Jochen Bedersdorfer; 02.05.2012