创建Java对象一般问题

时间:2011-01-03 20:04:08

标签: java memory object

哪种内存管理或任何其他原因更好,或者这两种情况相同:

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 个答案:

答案 0 :(得分:7)

要明确,日历实际上并不是单身人士。 Calendar.getInstance()每次调用它时都会返回一个新对象。

这意味着您的问题的答案取决于函数getSomething()和getBar()是否具有导致foo存储新Calendar实例的副作用。一般来说,良好的编程习惯要求不会出现这种情况。

编辑:但是,每次调用Calendar.getInstance()时,最终都会有不同的日期。这可能是一个重要的细节,具体取决于您的功能。

编辑2:它还取决于您执行上述过程的频率。正如另一个答案所指出的,实例化Calendar对象可能非常密集。如果你只做两次,那么缓存它并不重要。如果你经常这样做,那么你可以考虑改变你的方法或做一些缓存。

答案 1 :(得分:2)

Calendar是一个非常昂贵的对象(我所知道的任何库中最昂贵的日期对象之一)。调用getInstance()也非常昂贵。如果你必须使用Calendar,你可以看一下缓存它。这实际上取决于你为什么需要它。

获取和存储当前时间的最有效方法是使用long原语。

long currentDateTime = System.currentTimeMillis();

如果您在内部使用GMT时间,则可以使用

存储当天
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);

答案 2 :(得分:0)

  1. 使用更多内存和更少CPU
  2. 使用更少的内存和更多的CPU
  3. 您必须决定要为操作提供什么。 您的应用程序的瓶颈是什么?

答案 3 :(得分:0)

对于单身人士来说,它并没有太大的区别。通过使用临时变量,您可以节省函数调用的开销,但仅此而已 - 每次都返回相同的对象。

如果要通过调用构造函数或使用对象创建静态方法创建POJO,则需要创建新对象。这意味着您有函数调用的运行时开销,以及正在创建的另一个对象的内存开销。

通常,如果我计划在方法体内多次使用同一个对象,我将使用一个临时变量。这样,无论是否需要避免内存开销,我都在做同样的事情,而且我的代码会更加一致。

答案 4 :(得分:0)

您基本上看两种不同的情况: 1. Calendar是一个单例,在这种情况下,你必须调用一个helper方法来获取内存中的单个实例。 2.日历是POJO。如果getInstance()只是调用构造函数,那么每次调用它时都会创建一个新实例。因此,在后一种情况下,您可能会得到不同的意外结果。

但最重要的是,它归结为编码风格和可读性。一些开发人员更喜欢使用factory methods,有些人更喜欢直接调用构造函数。在我看来,如果对象是一个简单的实体(即不需要构建),那么调用new是创建对象最直接的方法。另一方面,如果涉及到一些构建,并且您通常需要更易读的代码,那么工厂方法更受欢迎。

从内存管理的角度来看,每次调用构造函数时,都会得到一个新的类实例。你打算使用那个新实例吗?您是否有对该新实例的引用可能会使其无法及时进行垃圾回收?那些问题有点多了。

答案 5 :(得分:0)

如果你只对从日历实例中读取感兴趣,那么第一种方法稍微好一点,因为垃圾收集器不会有太多工作要做,而且你只会存储/制作一个重量级对象。< / p>

答案 6 :(得分:0)

第一个块查询当前日期和时间一次。这很好,因为您可能希望对两者使用相同的时间戳。

第二个例子较慢,因为它必须初始化一个新的Calendar对象。也可能有两个不同的时间戳。问问自己,当第一个方法被调用时间为23:59:59.875,第二个方法被调用时间为00:00:00.007时,午夜时会发生什么。你真的想要吗?

技术上严格地说,第一个代码段声称某些内存的时间较长。但在几乎所有情况下你应该没问题,并使用第二个代码片段。

顺便说一句:您可以假设局部变量不会占用任何内存。特别是在经常使用的代码中,它们将被优化掉。

答案 7 :(得分:0)

  1. 使用更少的内存和更少的CPU
  2. 使用更多内存和更多CPU
  3. 垃圾收集器可以在最后一次使用之后立即收集Calendar实例。