我应该在构造函数中使用getter和setter吗?

8

在初始化类时,使用getter和setter函数作为构造函数的一部分是一个好的实践吗?

或者直接设置变量是否更好,因为构造函数可以被认为是一种修改器?


3
如果您的setter中有一些自定义代码,请使用它,否则将其简单地设置为this.x = x; - Kartik
4
在构造函数中使用getter似乎很危险(实例还在构建中,还没有可获取的内容),为什么要这样做?使用setter可能更合理。 - Elliott Frisch
@Kartik,除非你的setter被覆盖,否则你的自定义代码将不会运行。 - rghome
@rghome 说得好,但(我可能错了),如果您正在覆盖setter,几乎总是意味着您正在覆盖字段。在这种情况下,父类构造函数将毫无用处。 - Kartik
我认为答案并不一定是“不一定”。 - rghome
4个回答

16

在构造函数中不应调用getter和setter。

构造函数用于构造定义它的特定类。它的职责是初始化字段,因为其他方法可能还未生效。

保证初始化字段的唯一方法是直接赋值。如果调用setter,则有可能被覆盖且可能执行其他操作。它可能会调用尚未初始化的子类中的方法。

如果只是从同一个类获取字段,则调用getter也是不明智的。如果该字段已在超类中声明,则您可能会认为这样做有道理;如果需要从子类中获取超类的数据,则必须调用getter(除非它是受保护的)。如果需要在构造期间从子类向超类通信数据,则应将其作为参数传递。但这是与您所描述的用例不同,而子类可能根本没有对应于getter的自己的字段。

如果有任何“特殊”的初始化代码,请将其放在单独的私有方法中,并从构造函数和setter中分别调用它。


4
这要看你是否计划继承此类,是否允许别人继承你的类?
如果答案是否定的,则可以使用它,但是我认为这通常是不好的做法,原因如下:如果您没有明确禁止继承,则该类可以被子类化并覆盖方法,请参见以下引用。通常最好尽可能实现不可变性,并使用getter/setter保持不可变性。我还会争辩说,构造函数只应具有初始化班级到有效状态所必需的参数。如果也可以使用setter传递它们,则可能不需要使其达到有效状态。
如果您想设计您的类以支持继承,则答案是否,并且如果您使用init方法,则不能使用getter/setter或任何可以重写的方法。
以下是《Effective Java第二版》的直接引用:
“继承时类必须遵守的更多限制。构造函数不能调用可重写方法,直接或间接。如果违反此规则,程序将失败。超类构造函数在子类构造函数之前运行,因此子类中的重写方法将在子类构造函数运行之前被调用。如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将无法像预期那样工作。”

1
我认为,我可以使用setter来检查参数并/或在构造函数定义类时将其初始化为某些值。如果我有一个计算变量的情况,我也可以使用getter,但是我应该非常小心语句的顺序(不推荐容易出错的情况)。
JavaScript示例:
class Point {
  constructor (x, y) {
    this.x = x.x || x // invokes the setter
    this.y = x.y || y
  }
  toString () {
    return `The point is (${this.x}, ${this.y})` // invokes the getters
  }
  set x (newX) { // I think it should be better use 'newX' as a parameter than 'x'
    if (newX > 100) {
      console.log(`The x (${newX}) value must be < 100, `, 'x set to 0')
      this._x = 0 // if we use 'this.x' here, we will get an error (stack overflow)
      return
    }
    this._x = newX
  }
  get x () { // no one but the getter and setter should know '_x' exists
    return this._x // it has to be coherent with the setter
  }
  set y (newY) {
    if (newY > 100) {
      console.log(`The y (${newY}) value must be < 100, `, 'y set to 0')
      this._y = 0
      return
    }
    this._y = newY
  }
  get y () {
    return this._y
  }
}

1
我认为你的代码有错误。请仔细检查(似乎有很多额外的空格)。 - Tacratis
代码已经通过ESLint检查,没有任何错误。我还运行了一些测试代码,它可以正常工作。此外,我不知道你看到了多少额外的空格,我只是为了可读性缩进了代码,尽管它按预期工作。 - fenderOne
@Tacratis 哦,我没有意识到这个问题有一个“JAVA”标签,我用JavaScript写了例子。 - fenderOne

0
不,拥有访问器和修改器的目的是能够从同一包中的另一个类访问私有字段。
从构造函数中改变变量的值技术上是可行的,但这违背了初始化的目的。访问变量只是为获取其内容添加了额外的步骤。
因此,是的,您应该直接重新分配要赋给变量的值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接