从构造函数中调用setter

Bil*_*ory 62 java oop

从构造函数(如果有的话)调用mutator的pro和con是什么

即:

public MyConstructor(int x) {
  this.x = x;
}
Run Code Online (Sandbox Code Playgroud)

与:

public MyConstructor(int x) {
  setX(x);
}

public void setX(int x) {
  this.x = x;
}
Run Code Online (Sandbox Code Playgroud)

你有偏好吗?(这不是功课,只是查看我们的编码标准文档,它说在构造函数中设置实例var时始终会调用mutator而我并不总是这样做)

Jon*_*eet 78

就个人而言,我会在大多数情况下直接设置变量.

方法通常期望实例在被调用时完全形成.特别是,从构造函数调用重写方法是一个难以理解的代码和难以发现的错误的秘诀.

话虽如此,我经常尝试使类无法变换,在这种情况下,不仅没有setter,而且你必须从构造函数(或变量初始化程序)设置最终变量:)

在属性具有逻辑的情况下,setter逻辑通常是验证,有时会改变传播给观察者.我通常希望在方法开始时显式检查构造函数参数,并且在完全创建实例之前,您不希望发生任何更改传播.


Ber*_*t F 30

我遵循两个关于构造函数的规则来最小化问题,这就是为什么我不使用mutator方法:

构造函数(非最终类)应该只调用final或private方法.如果您决定忽略此规则并让构造函数调用非final/non-private方法,则:

  • 那些方法和他们可能调用的任何方法必须小心,不要假设实例已完全初始化,并且
  • 覆盖这些方法的子类(甚至可能不知道超类构造函数调用这些方法的子类)不能假定子类构造函数和超类的构造函数已经完全执行.使用"邪恶"构造函数的超类继承层次结构越深,这个问题就越严重.

是否值得拥有额外的认知包袱?你可以允许简单的mutator例外,它只为一个实例变量赋值,因为它没什么好处,即使看起来不值得.

[[@Jon Skeet在他的回答中提到了这一点:"......特别是,从构造函数中调用重写方法是一个难以理解的代码和难以发现的错误的秘诀." 但我认为这个问题的后果不够强调.]]

this在实例完全初始化之前,构造函数应该对泄漏保持谨慎.虽然之前的规则是关于类中的方法和访问ivars的子类,但thisthis完全初始化之前,还必须注意(甚至是final/private)方法传递给其他类和实用程序函数.构造函数调用的非私有,可覆盖的方法越多,泄漏的风险就越大this.


关于构造函数调用非最终非私有方法的一些引用:

https://www.securecoding.cert.org/confluence/display/java/MET05-J.+Ensure+that+constructors+do+not+call+overridable+methods

http://www.javaworld.com/article/2074669/core-java/java-netbeans--overridable-method-call-in-constructor.html

http://www.javaspecialists.eu/archive/Issue210.html

  • +1"是否值得拥有额外的认知包袱?" 没有! (2认同)

Tim*_*rJD 5

在构造函数中调用任何public, static,non-final方法取决于您,但最佳实践是永远不要在构造函数中调用此类方法,因为这些方法可以在子类中被覆盖,实际上只会调用此方法的覆盖版本(如果您使用多态行为) .

例如:

public class Foo {

    public Foo() {
        doSmth(); // If you use polymorphic behavior this method will never be invoked
    }

    public void doSmth() {
        System.out.println("doSmth in super class");
    }

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

class Bar extends Foo {

    private int y;;

    public Bar(int y) {
        this.y = y;
    }

    @Override
    public void doSmth() { // This version will be invoked even before Barr object initialized
        System.out.println(y);
    }

}
Run Code Online (Sandbox Code Playgroud)

它将打印 0。

有关详细信息,请阅读Bruce Eckel “Thinking in Java”一章“Polymorphism”