2

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

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

    //...
}

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

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

4

7 回答 7

2

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

只谈性能,这取决于你的使用。

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

如果您创建很多As 并且只调用method几次,则第二个会更好。(正如@Marko Topolnik 建议的那样)

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

这个问题比性能重要得多。

于 2013-11-05T12:18:09.723 回答
1

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

于 2013-11-05T12:27:10.503 回答
1

这取决于。

表现

如果您想像这里一样评估两个抽象选项之间的性能差异;最好的方法是夸大一切的规模。例如,假设SomeObject实例化需要大量时间(例如,600 秒),并且您计划调用method()很多(因为性能问题通常要等到项目规模扩大后才会意识到)。

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

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

建筑学

选项 2

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

选项1

好吧,但也许SomeObject是暴露业务逻辑的服务或外观。正如您在问题中提到的那样,它“更适合测试”,完整的答案是,是的,它为依赖注入提供了一个更简单的钩子,这是单元测试的关键组成部分。(虽然,通常它会被重写为private SomeObject a;,构造函数喜欢public a (SomeObject a) { this.a = a; }遵循控制范式的依赖注入/反转。但是,对于这个问题的目的,最终结果是相同的。)

对于(设计良好的)服务或实用程序功能,您希望它自己(私下)处理对象处置。在这种情况下,更常用的模式是选项 1,因为它为您提供了一个管理依赖关系的地方,而不是在每个使用它的方法中。

你的选择

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

  • 选项 1 - 服务、立面、实用程序等。
  • 选项 2 - 需要处理的对象;实现Closable, StreamReader, FileWriter, 等的对象
于 2013-11-05T12:34:19.757 回答
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() 时创建一个对象。

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

于 2013-11-05T13:04:52.550 回答
1

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

public class A{
   private SomeObject o;

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

此外,将引用标记为 final可能有助于提高性能(至少以前如此):

public class A{
       private final SomeObject = new SomeObject();
       ....
}
于 2013-11-05T13:31:43.287 回答
1

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

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

但值得注意的是,第一个代码someObject中的 不是在每次调用method. 我不知道你打了多少次电话method,你的问题在目前的版本中很难回答。

于 2013-11-05T12:17:40.143 回答
0

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

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

于 2013-11-05T12:18:16.557 回答