创建Java对象一般问题

发布于 2024-10-10 19:09:32 字数 432 浏览 5 评论 0原文

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

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,答案会改变吗?

Which is better for memory management, or any other reason, or are these two scenarios the same:

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

The other code block:

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

The general question is, is it better to get an instance of an object, then use that instance when needed, or make the getInstance() call each time when needed.
And, does the answer change if not dealing with a singleton, but making a plain POJO?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

岁月打碎记忆 2024-10-17 19:09:33
  1. 使用更少的内存和更少的 CPU
  2. 使用更多的内存和更多的 CPU

垃圾收集器可以在最后一次使用对 Calendar 实例的引用后立即收集它。

  1. uses less memory and less CPU
  2. uses more memory and more CPU

The garbage collector is free to collect the Calendar instance immediately after the last use of a reference to it.

花桑 2024-10-17 19:09:32

需要明确的是,Calendar 实际上并不是单例。每次调用 Calendar.getInstance() 时都会返回一个新对象。

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

编辑:但是,每次调用 Calendar.getInstance() 时,您可能会得到不同的日期。这可能是一个重要的细节,具体取决于您的函数正在执行的操作。

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

To be clear, Calendar is not actually a singleton. Calendar.getInstance() returns a new object each time you call it.

This means that the answer to your question depends on whether or not the functions getSomething() and getBar() have side effects that cause foo to store the new Calendar instance. In general, good programming practices dictate that this won't be the case.

EDIT: However, each time you call Calendar.getInstance() you could end up with a different date. This may be an important detail depending on what your functions are doing.

EDIT 2: it also depends on how often you do the above process. As another answer pointed out, instantiating Calendar objects can be intensive. If you only do it twice, then it doesn't matter if you cache it. If you do this very often, then you may consider changing your approach or doing some caching.

别靠近我心 2024-10-17 19:09:32

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

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

long currentDateTime = System.currentTimeMillis();

如果您在内部使用 GMT 时间,则可以使用 EDIT 存储当前日期

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);

Calendar is a very expensive object (one of the most expensive date objects in any library I know of). Calling getInstance() is very expensive too. If you have to use Calendar you could look at caching it. It really depends on why you need it.

The most efficient way to obtain and store the current time is using a long primitive.

long currentDateTime = System.currentTimeMillis();

If you use GMT time internally, you can store the current day with

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

EDIT: It is worth testing on your machine, while getInstance() is relatively expensive but it is still fairly fast. On my old box it takes ~20 micro-seconds. On a fast machine currentTimeMillis() can take 140 nano-seconds.

The following prints

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

code

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);
俯瞰星空 2024-10-17 19:09:32

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

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

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

For a singleton, it doesn't make much of a difference. By using a temporary variable, you are saving the overhead of a function call, but nothing more - the same object is being returned each time.

If you are making a POJO, either by calling a constructor or by using an object-creation static method, you are creating a new object. This means that you have the run-time overhead of a function call, as well as the memory overhead of another object being created.

In general, if I am planning on using the same object several times within a method body, I will use a temporary variable. This way, I am doing the same thing whether I need to avoid memory overhead or not, and my code will be more consistent for it.

离鸿 2024-10-17 19:09:32
  1. 使用更多内存和更少 CPU
  2. 使用更少内存和更多 CPU

您必须决定要为操作提供什么。
您的应用程序的瓶颈是什么。

  1. uses more memory and less CPU
  2. uses less memory and more CPU

You have to decide what you want to give for the operation.
What is the bottleneck in your application.

带上头具痛哭 2024-10-17 19:09:32

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

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

从内存管理的角度来看,每次调用构造函数时,您都会获得该类的一个新实例。您要使用那个新实例吗?您是否有对该新实例的引用,可能会阻止其及时被垃圾收集?这些问题有点元。

You are basically looking at two different scenarios:
1. Calendar is a singleton, in which case you will have to call a helper method to get the single instance that is in memory.
2. Calendar is a POJO. If getInstance() simply calls the constructor, then you will be creating a new instance every time you invoke it. As such, you may be getting different unexpected results in your latter case.

The bottom-line, though, is that it comes down to coding-style and readability. Some developers prefer using factory methods, some prefer simply calling the constructor directly. In my mind, if the object is a simple entity (i.e. no build-up required), then calling new is the most straight-forward method of creating an object. If, on the other hand, there is some build-up involved, and you want generally more readable code, then a factory method is much more preferred.

From a memory-management perspective, every time you call the constructor, you will get a new instance of the class. Are you going to use that new instance? Do you have references to that new instance that might keep it from being garbage collected in a timely manner? Those questions are a bit more meta.

温馨耳语 2024-10-17 19:09:32

如果您只对读取日历实例感兴趣,则第一种方法稍微好一些,因为垃圾收集器不会有太多工作要做,并且您只会存储/制作一次重量级对象。

If you are only interested in reading from the calendar instance the first method is marginally better, since the garbage collector won't have quite so much work to do, and you will only be storing/making a heavyweight object once.

哭泣的笑容 2024-10-17 19:09:32

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

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

从技术上和严格意义上讲,第一个代码片段占用了一些较长时间的内存。但在几乎所有情况下,您都应该接受并使用第二个代码片段。

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

The first block queries the current date and time once. This is good, since you probably want to use the same timestamp for both.

The second example is slower since it has to initialize a new Calendar object. Also there may be two different timestamps. Ask yourself what will happen around midnight when the first method is called with a time of 23:59:59.875 and the second method is called with a time of 00:00:00.007. Do you really want that?

Technically and strictly the first code snippet claims some memory for a longer time. But in pretty much all cases you should be fine with that and go with the second code snippet.

And by the way: You can assume that local variables don't cost any memory. Especially in often-used code they will be optimized away.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文