如何在Java中初始化对象 - 使用字段或局部变量?

时间:2013-11-05 12:14:11

标签: java performance initialization

以下情况的性能/可靠性图如何:

public class A {
    private SomeObject a = new SomeObject();

    //...

    public void method() {
        a.callSomeMethod();
    }

    //...
}

public class A {
    //...

    public void method() {
        SomeObject a = new SomeObject();
        a.callSomeMethod();
    }

    //...
}

我明白了,从可测试性的角度来看,第二种选择并不是那么好。 但是性能,可靠性如何 - 你应该走哪条路?要将对象初始化为一个文件并大量使用它或在每次需要时启动它?

稍后编辑:对象的构造不需要很长时间。该方法被大量使用。

7 个答案:

答案 0 :(得分:2)

性能问题不是这里最大的问题。

仅谈性能,取决于您的使用情况。

第一个版本可以更好,因为您不会在每个方法调用中创建新的SomeObject

如果您创建了大量A s并且只调用method几次,则第二个更好。 (正如@Marko Topolnik建议的那样)

但是,这里最大的问题是正确性。在method的每次通话中使用相同的对象与每次通话时使用新的SomeObject不同。

这个问题比表现更重要。

答案 1 :(得分:1)

  

以下情况的性能/可靠性图片如何

它们完全不同,在第一种情况下a是一个类成员,在第二种a中仅在method的范围内知道。我不确定“比较”这两个代码的性能有多好。

但值得注意的是,someObject的每次调用都不会创建第一个代码method。我不知道你打电话method多少次,你的问题在目前的修订中难以回答。

答案 2 :(得分:1)

实际上,如果你的SomeObject构造函数体包含执行可能需要很长时间的代码,那么在第二种情况下可能存在一些真正的性能问题,因为在第二种情况下,每次SomeObject构造A.method()对象时正在调用{1}}。

答案 3 :(得分:1)

取决于。

效果

如果您想评估两个抽象选项之间的性能差异,就像您在这里一样;最好的方法是夸大一切的规模。例如,假设SomeObject需要花费过多的时间来实例化(例如,600秒),并且您计划大量调用method()(因为在项目之前通常无法实现性能问题尺度)。

很明显:选项1将在多个method()调用中“执行”更好,因为选项2每次调用方法时都会导致巨大的操作。 (是的,作为粗略的性能测试,您可以通过for循环运行每个选项并比较经过的时间,但应该很容易看到:所有其他都相同,创建一个对象n次将需要更多时间比创建一个对象一样。)

但在夸张的例子中表现本身并不一定是在所有情况下都支持选项1的理由。

建筑

选项2

它真正归结为SomeObject的架构。 SomeObject的内容是什么?可能SomeObject是一个在A的生命周期内无法保持打开的对象;例如,它可能是某种流式读取器,它在从流中读取资源时锁定资源。在这种情况下,您可能不希望SomeObject一直“打开”阻止该资源;它应该在method()电话结束时处理

选项1

好吧,但也许SomeObject就像服务或Facade那样暴露了业务逻辑。正如你在问题中提到的那样,它“更适合测试”,而完全答案是,是的,它为依赖注入提供了一个更容易的钩子,这是单元测试的关键组件。 (虽然,通常它将被重写为private SomeObject a;,使用类似public a (SomeObject a) { this.a = a; }的构造函数来遵循控制范例的依赖注入/反转。但是,最终结果是相同的这个问题。)

对于(精心设计的)服务或实用程序功能,您希望它本身(私下)处理对象处理。在这种情况下,使用得更多的模式是选项1,因为它为您提供了一个管理依赖项的位置,而不是在使用它的每个方法中。

您的选择

了解上述内容应足以做出明智的决定。

  • 选项1 - 服务,外墙,公用设施等
  • 选项2 - 需要处置的物体;实现Closable的对象,如StreamReaderFileWriter

答案 4 :(得分:1)

是。表现会受到打击。在第一个场景中,每次输入method()时都不会创建SomeObject的对象。在第二种情况下,每次输入method()时,都会创建一个新的SomeObject,这通常不是优选的。但另一方面,还必须查看对象和垃圾收集机制的范围。在第二种情况下,只要方法调用返回/结束,创建的对象的范围也会丢失。因此,它将可用于垃圾收集器。所以,如果内存是一个问题,那么你可能想要第二个选项。即,如果要创建几百个对象,那么您可能需要考虑第二个选项。选项1的缺点是只要父对象 - 类A的实例存在,所有组合对象都将持久存在。如果你继续这样做

public class A {
    private SomeObject a1 = new SomeObject();
    private SomeObject a2 = new SomeObject();

    private SomeObject a1000 = new SomeObject();
    //...

    public void method() {
        a.callSomeMethod();
    }

//...

}

上面的代码效率低于使用for循环和调用method()1000次并且每次调用method()时都创建一个对象。

但话又说回来,这是一个设计问题。根据您的需求,一种选择比另一种更好。 如果我错了,请纠正我。

答案 5 :(得分:1)

其他答案已经涵盖了这一点,所以我不会重复太多。这实际上取决于ASomeObject的用途和结构。根据具体情况,还有其他选择。如果对象创建是SomeObject的问题,并且对method的调用次数相对较少,则使用延迟初始化可能有意义:

public class A{
   private SomeObject o;

   public void method(){
       if(o == null){
            o = new SomeObject();
       }
       o.callSomeMethod();
   }
}

此外,将引用标记为最终可能有助于提高性能(至少用于):

public class A{
       private final SomeObject = new SomeObject();
       ....
}

答案 6 :(得分:0)

主要区别在于变量的范围。第一个是实例变量,后来是局部变量。

如果Object将仅在该方法中使用并且将在每次调用时更改,那么您可以采用第二种方法