在调用构造函数而不是在构造函数中设置实例的变量有什么好处吗?

时间:2009-06-13 23:01:20

标签: java

例如:

public class Foo {
    private int bar = 42;

    Foo() {}
}

VS

public class Foo {
    private int bar;

    Foo() {
        bar = 42;
    }
}

两种方法之间有任何成本/收益吗?我能看到它有所作为的唯一方法是在这样的场景中(你为第二个构造函数设置两次值):

public class Foo {
    private int bar = 42;

    Foo() {}

    Foo(int in) {
        bar = in;
    }
}

vs(无论哪种方式,你只设置一次)

public class Foo {
    private int bar;

    Foo() {
        this(42);
    }

    Foo(int in) {
        bar = in;
    }
}

我错过了什么吗?这样或那样做是否有任何内在价值?

修改

好的,我意识到这些功能是等效的,我想弄清楚的是,如果有一个重要的处理成本与另一个相关联。似乎它应该是可以忽略的,充其量,但我想确认我的怀疑。

编辑2

我也意识到手动设置它们可以消除启动逻辑的可能性。这就是我选择这么简单的例子的原因。我编辑了问题文本,以反映我感兴趣的是效率。

5 个答案:

答案 0 :(得分:11)

这两种方法是等价的。话虽如此,我还会添加两件事:

  1. 这对于最终变量来说往往是一个问题,因为显然你只能像在第三个片段中那样设置它们一次;和
  2. 尝试将构造函数链接在一起。
  3. On(2)我认为这是一个更好的版本:

    public class Foo {
        private int bar;
    
        Foo() {
            this(42);
        }
    
        Foo(int in) {
            bar = in;
        }
    }
    

    通过链接构造函数,您可以获得一个漂亮的DRY(不要重复自己)的默认默认值,特别是在处理可能具有默认参数,各种允许类型的参数和非平凡初始化的几个参数时。理想情况下,只有一个或两个构造函数应该具有重要的逻辑。其余的应该链接到另一个构造函数。

    如果你想让这个类不可变(正如Josh Bloch所说,赞成不变性)那么:

    public class Foo {
        private final int bar;
    
        Foo() {
            this(42);
        }
    
        Foo(int in) {
            bar = in;
        }
    }
    

    最后,可能值得将42作为静态最终常量(私有或公共,视情况而定)。

答案 1 :(得分:2)

在构造函数中初始化变量是有好处的。有时初始化需要逻辑,如果在第一个示例中设置了变量的值,则无法完成初始化。然而,其他人对可维护性的观点是有效的。

但是Java为我们提供了初始化块。初始化程序块由编译器复制到每个构造函数中。因此,如果您担心构造函数不一致,那么您可以这样做:

 public class Foo {
   private int bar;

   //initializer block
   {
      //initializing code here
   }

   Foo() {

   }
 }

你拥有的第二个选项是按照cletus的描述链接构造函数。

答案 2 :(得分:0)

我个人更喜欢第一种方式,因为它更清楚var的值最初是什么。

答案 3 :(得分:0)

在构造函数中将字段设置为默认值的主要风险是人们开始添加多个构造函数并且不保持字段一致。

我对遗留Java代码的(不科学的)经验是,如果有两个以上的构造函数和两个以上的字段,80%的时间都无法正确初始化。

答案 4 :(得分:0)

当你的成员变量是final并且你有一个从父的构造函数调用的方法时,有一点点不同(这是一个BAD实践,请不要这样做。)

以下代码的输出为:

early = 42
late = 0

这是测试代码:

class Test {

    private static class Base{

        Base() {
            doInConstructor();
        }

        protected void doInConstructor() {

        }
    }

    private static  class Derived extends Base {
        final int early = 42;
        final int late;

        Derived() {
            late = 84;
        }

        protected void doInConstructor() {
            super.doInConstructor();
            System.out.println("early = " + early);
            System.out.println("late = " + late);
        }
    }

    public static void main(String[] args) {
        new Derived();
    }
}