是否有可变 public 字段的用例?
Are there use-cases for mutable public fields?
我想知道是否存在 public 字段合理的用例(对于可变值),或者应该不惜一切代价避免使用 getters/setters 应该始终使用。
假设有一个 DTO(数据传输对象)/Java Bean,它没有任何逻辑,只是保存数据(添加更多这可能是协议的一部分,它不会改变,只会增强) .
实际上不存在要封装的实现细节,因为没有实现,只有数据。
还假设 Bean Validation 框架用于通过注释验证对象,因此没有用于验证逻辑的 setter 的目的。
为什么 setter 和 getter 会打扰我?
没有setters/getters更容易阅读;字段,尤其是内部 类 (您不必滚动到 setter 和 getter 即可到达其他字段)。此外,user.password
比 user.getPassword()
更清楚,如 Groovy.
我知道龙目岛项目;但我已经有很多来自 Bean Validation 的注释。
所以要弄清楚这个问题:上述情况是否适用于 public 个字段,还是 setters/getters 更好? 为什么?
might the above scenario be justified for public fields or is it still better to have setters/getters?
情况似乎是您对滚动 getter 和 setter 感到困扰。这在我的书中不是一个很好的理由,但如果你可以保持这些 类 包私有或私有嵌套 类,那么 Joshua Bloch 没问题,因为未来可能发生变化的范围。
有效 Java 项目 14: 在 public 类 中,使用访问器方法,而不是 public 字段
If a public class exposes its
data fields, all hope of changing its representation is lost, as client code can be distributed
far and wide.
However, if a class is package-private or is a private nested class, there is
nothing inherently wrong with exposing its data fields - assuming they do an adequate job of describing the abstraction provided by the class.
就我个人而言,我比较严格,我遵循的经验法则是字段在 编译单元 之外不得可见。例如:
public class Outer {
private int fieldMustBePrivate;
public class PublicNested {
private int fieldMustBePrivate;
}
private class PrivateNested {
int fieldOkToBePackagePrivate;
}
public void exampleUsage() {
PrivateNested privateNested = new PrivateNested();
privateNested.fieldOkToBePackagePrivate = 123;
}
}
一个常见的情况是,有时在实施或执行的中间,您发现您的记录以空用户名结尾。
现在,您可以:
搜索所有被属性赋值的地方,查找被赋值为null的地方。它可能是 20 个位置,而且很可能不会是 user.userName = null
,而是 String userName = null; ..... user.userName = userName
。
向您的 setUserName()
方法添加一个检查,该方法在尝试设置空值时启动异常。您获得了完整的堆栈跟踪,并且程序的运行在 将错误数据引入您的持久层之前停止。
因此,直接访问属性的用例是当您确定您的代码中绝对没有(并且将会)没有错误时。
我会坚持使用二传手。
此外,一些(许多)框架依赖于使用 setter 和 getter 来访问属性。
目前的观点是你应该不有可变的public字段。
它来自两个不同方向的Principle of least astonishment。
首先,通常的做法是将所有字段设为私有,只能通过 getter 和 setters 进行访问。有很多代码可以做到这一点,当您遇到不这样做的代码时,令人惊讶。
其次,它给了你可预测性。您可以保证 没有人会在您的 setter 以外的任何地方更改字段。因此,您可以在 setter 上放置一个断点,并且 知道 对该字段的每次更改都会到达断点。
但是,有一些纯数据情况,就像您描述的那样,很容易在其中创建字段 public,甚至更罕见,不是最终的。
我的工具箱中有一个 class Pair
,其中有 public 个字段:
public class Pair<P, Q> {
// Exposing p & q directly for simplicity. They are final so this is safe.
public final P p;
public final Q q;
public Pair(P p, Q q) {
this.p = p;
this.q = q;
}
是的,有:
- 性能
- 代码简洁
调用一个函数(accessors/mutators 是函数)可能看起来没什么大不了的,但是当翻译成汇编代码时,这意味着你必须将函数参数压入堆栈,压入 return地址入栈,执行一个CALL函数,执行函数体,然后将结果压入栈中,弹出原始参数,弹出return地址并转到原始地址......这取决于略有不同关于调用约定,我可能以错误的顺序列举了步骤,但通常调用函数时确实会产生开销。
因此,对于像 getter/setter 这样可能只包含一两个汇编指令的愚蠢函数,开销与有效负载的数量级相同,甚至可能更大。如果您正在开发游戏或任何其他对性能要求很高的软件,摆脱函数调用是优化技术之一。
关于第二个用例,代码简洁,getter 和 setter 什么都不做(他们不做验证,不同步,不复制,什么都不做)实际上是多余的,我们只是代码他们,因为这是 Java 中的惯例。但它们毫无用处。其他人(例如:Google)不要盲目地遵循这个约定。
较新的语言通常会提供一些机制来自动创建这些方法,甚至完全跳过它们,依靠成员访问修饰符来提供封装。例如,C#'s properties 提供自动 getter/setter,但允许您的代码调用它们,就好像它们是 public 成员一样。
我想知道是否存在 public 字段合理的用例(对于可变值),或者应该不惜一切代价避免使用 getters/setters 应该始终使用。
假设有一个 DTO(数据传输对象)/Java Bean,它没有任何逻辑,只是保存数据(添加更多这可能是协议的一部分,它不会改变,只会增强) . 实际上不存在要封装的实现细节,因为没有实现,只有数据。 还假设 Bean Validation 框架用于通过注释验证对象,因此没有用于验证逻辑的 setter 的目的。
为什么 setter 和 getter 会打扰我?
没有setters/getters更容易阅读;字段,尤其是内部 类 (您不必滚动到 setter 和 getter 即可到达其他字段)。此外,user.password
比 user.getPassword()
更清楚,如 Groovy.
我知道龙目岛项目;但我已经有很多来自 Bean Validation 的注释。
所以要弄清楚这个问题:上述情况是否适用于 public 个字段,还是 setters/getters 更好? 为什么?
might the above scenario be justified for public fields or is it still better to have setters/getters?
情况似乎是您对滚动 getter 和 setter 感到困扰。这在我的书中不是一个很好的理由,但如果你可以保持这些 类 包私有或私有嵌套 类,那么 Joshua Bloch 没问题,因为未来可能发生变化的范围。
有效 Java 项目 14: 在 public 类 中,使用访问器方法,而不是 public 字段
If a public class exposes its data fields, all hope of changing its representation is lost, as client code can be distributed far and wide.
However, if a class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields - assuming they do an adequate job of describing the abstraction provided by the class.
就我个人而言,我比较严格,我遵循的经验法则是字段在 编译单元 之外不得可见。例如:
public class Outer {
private int fieldMustBePrivate;
public class PublicNested {
private int fieldMustBePrivate;
}
private class PrivateNested {
int fieldOkToBePackagePrivate;
}
public void exampleUsage() {
PrivateNested privateNested = new PrivateNested();
privateNested.fieldOkToBePackagePrivate = 123;
}
}
一个常见的情况是,有时在实施或执行的中间,您发现您的记录以空用户名结尾。
现在,您可以:
搜索所有被属性赋值的地方,查找被赋值为null的地方。它可能是 20 个位置,而且很可能不会是
user.userName = null
,而是String userName = null; ..... user.userName = userName
。向您的
setUserName()
方法添加一个检查,该方法在尝试设置空值时启动异常。您获得了完整的堆栈跟踪,并且程序的运行在 将错误数据引入您的持久层之前停止。
因此,直接访问属性的用例是当您确定您的代码中绝对没有(并且将会)没有错误时。
我会坚持使用二传手。
此外,一些(许多)框架依赖于使用 setter 和 getter 来访问属性。
目前的观点是你应该不有可变的public字段。
它来自两个不同方向的Principle of least astonishment。
首先,通常的做法是将所有字段设为私有,只能通过 getter 和 setters 进行访问。有很多代码可以做到这一点,当您遇到不这样做的代码时,令人惊讶。
其次,它给了你可预测性。您可以保证 没有人会在您的 setter 以外的任何地方更改字段。因此,您可以在 setter 上放置一个断点,并且 知道 对该字段的每次更改都会到达断点。
但是,有一些纯数据情况,就像您描述的那样,很容易在其中创建字段 public,甚至更罕见,不是最终的。
我的工具箱中有一个 class Pair
,其中有 public 个字段:
public class Pair<P, Q> {
// Exposing p & q directly for simplicity. They are final so this is safe.
public final P p;
public final Q q;
public Pair(P p, Q q) {
this.p = p;
this.q = q;
}
是的,有:
- 性能
- 代码简洁
调用一个函数(accessors/mutators 是函数)可能看起来没什么大不了的,但是当翻译成汇编代码时,这意味着你必须将函数参数压入堆栈,压入 return地址入栈,执行一个CALL函数,执行函数体,然后将结果压入栈中,弹出原始参数,弹出return地址并转到原始地址......这取决于略有不同关于调用约定,我可能以错误的顺序列举了步骤,但通常调用函数时确实会产生开销。
因此,对于像 getter/setter 这样可能只包含一两个汇编指令的愚蠢函数,开销与有效负载的数量级相同,甚至可能更大。如果您正在开发游戏或任何其他对性能要求很高的软件,摆脱函数调用是优化技术之一。
关于第二个用例,代码简洁,getter 和 setter 什么都不做(他们不做验证,不同步,不复制,什么都不做)实际上是多余的,我们只是代码他们,因为这是 Java 中的惯例。但它们毫无用处。其他人(例如:Google)不要盲目地遵循这个约定。
较新的语言通常会提供一些机制来自动创建这些方法,甚至完全跳过它们,依靠成员访问修饰符来提供封装。例如,C#'s properties 提供自动 getter/setter,但允许您的代码调用它们,就好像它们是 public 成员一样。