Создание Java-объекта общий вопрос - PullRequest
3 голосов
/ 03 января 2011

Что лучше для управления памятью, или по любой другой причине, или эти два сценария одинаковы:

Calendar currentDateTime = Calendar.getInstance();
int i= foo.getSomething(currentDateTime);
Bar bar= foo.getBar(currentDateTime);

Другой кодовый блок:

int i= foo.getSomething(Calendar.getInstance());
Bar bar= foo.getBar(Calendar.getInstance());

Общий вопрос заключается в том, лучше ли получить экземпляр объекта, затем использовать этот экземпляр при необходимости или выполнять вызов getInstance () каждый раз, когда это необходимо. И изменится ли ответ, если не иметь дело с синглтоном, а сделать простой POJO?

Ответы [ 8 ]

7 голосов
/ 03 января 2011

Чтобы быть ясным, Календарь на самом деле не одиночка. Calendar.getInstance () возвращает новый объект каждый раз, когда вы вызываете его.

Это означает, что ответ на ваш вопрос зависит от того, имеют ли функции getSomething () и getBar () побочные эффекты, которые заставляют foo хранить новый экземпляр Calendar. В общем, хорошие практики программирования диктуют, что это не так.

РЕДАКТИРОВАТЬ: Однако каждый раз, когда вы вызываете Calendar.getInstance (), вы можете получить другую дату. Это может быть важной деталью в зависимости от того, что делают ваши функции.

РЕДАКТИРОВАТЬ 2: это также зависит от того, как часто вы делаете вышеупомянутый процесс. Как указал другой ответ, создание экземпляров объектов Calendar может быть интенсивным. Если вы делаете это только дважды, тогда не имеет значения, если вы кешируете это. Если вы делаете это очень часто, вы можете изменить свой подход или заняться кэшированием.

2 голосов
/ 03 января 2011

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

Самый эффективный способ получить и сохранить текущее время - использовать длинный примитив.

long currentDateTime = System.currentTimeMillis();

Если вы используете время по Гринвичу внутри, вы можетесохранить текущий день с

int currentDay = (int)(System.currentTimeMillis() / 86400000);

РЕДАКТИРОВАТЬ: стоит проверить на вашей машине, в то время как getInstance () является относительно дорогим, но все еще довольно быстро.На моей старой коробке это занимает ~ 20 микросекунд.На быстрой машине currentTimeMillis () может занять 140 наносекунд.

Следующие отпечатки

Calendar.getInstance() took on average 20088 ns. java.util.GregorianCalendar[time=1294086899359 ... deleted ...]
System.currentTimeMillis() took on average 938 ns. 1294086899377

код

int runs = 10000;
long start = System.nanoTime();
Calendar cal = null;
for(int i=0;i<runs;i++)
    cal = Calendar.getInstance();
long time = System.nanoTime() - start;
System.out.println("Calendar.getInstance() took on average "+time/runs+" ns. "+cal);

long start2 = System.nanoTime();
long now = 0;
for(int i=0;i<runs;i++)
    now = System.currentTimeMillis();
long time2 = System.nanoTime() - start2;
System.out.println("System.currentTimeMillis() took on average "+time2/runs+" ns. "+now);
0 голосов
/ 03 января 2011
  1. использует меньше памяти и меньше ресурсов процессора
  2. использует больше памяти и больше ресурсов процессора

Сборщик мусора может собирать экземпляр Calendar сразу после последнего используйте ссылки на него.

0 голосов
/ 03 января 2011

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

Второй пример медленнее, поскольку он должен инициализировать новый Calendar объект. Также могут быть две разные временные метки. Спросите себя, что произойдет около полуночи, когда первый метод вызывается со временем 23:59:59.875, а второй метод вызывается со временем 00:00:00.007. Вы действительно этого хотите?

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

И, между прочим: Вы можете предположить, что локальные переменные не стоят никакой памяти. Особенно в часто используемом коде они будут оптимизированы.

0 голосов
/ 03 января 2011

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

0 голосов
/ 03 января 2011

Вы в основном смотрите на два разных сценария: 1. Календарь является одноэлементным, и в этом случае вам нужно будет вызвать вспомогательный метод, чтобы получить единственный экземпляр, который находится в памяти. 2. Календарь - это POJO. Если getInstance () просто вызывает конструктор, то вы будете создавать новый экземпляр каждый раз, когда вызываете его. Таким образом, в последнем случае вы можете получить другие неожиданные результаты.

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

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

0 голосов
/ 03 января 2011

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

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

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

0 голосов
/ 03 января 2011
  1. использует больше памяти и меньше CPU
  2. использует меньше памяти и больше CPU

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...