这两种方法都有效,但这是正确的方法吗?
方法一:
public class Object {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object(String name){
this.name = name;
}
}
方法二:
public class Object {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//Changed this.name = name to setName(name)
public Object(String name){
setName(name);
}
}
我已经四处搜索,但无法找到提及此问题的确切问题。如果有,可以免费发布链接,我将删除问题
答案 0 :(得分:6)
我的第一个想法是在构造函数中使用setter。因此,如果您想要更改名称的存储方式,或者如果您想在设置名称时添加任何其他行为,则只需更改一次。
但是考虑到这一点,我认为如果类不是 final 并且方法不是私有,那么使用对变量的直接访问会更好。否则有人可以扩展你的方法,覆盖方法,导致你的构造函数以不可预测的行为调用他们的方法。
经验法则: 如果该类不是final,则只应在构造函数中调用private方法。
答案 1 :(得分:4)
虽然在构造函数中使用setter可以减少代码重复,但是不鼓励在构造函数中调用可重写方法(即非final /非私有方法) - 在扩展类时可能会导致奇怪的错误。
考虑以下情况(基于您的示例):
public class Object {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//Changed this.name = name to setName(name)
public Object(String name){
setName(name);
}
}
使用以下子类:
public class SubObject extends Object {
private String Id;
@Override
public void setName(String name) {
super.setName(name + Id);
}
public SubObject(String name){
super(name);
this.id = "1";
}
}
创建SubObject
的实例将导致空指针,因为setName()
在构造函数中被调用,但setName()
的实现依赖于Id
字段初始化。
扩展类的人不应该去检查超类的源代码,以确保构造函数不调用可重写的方法。
答案 2 :(得分:2)
我不会在构造函数中使用setter。这是因为如果有人在设置器中设置名称时添加了任何其他行为,我认为这是附带效果。
答案 3 :(得分:2)
如果所有的setter和构造函数都是一个简单的赋值,那么选择哪两种方式并不重要。
但是,如果在将新值分配给成员之前需要执行一些验证,那么将该逻辑放在一个地方是有意义的,这意味着从构造函数中调用setter方法是更好的选择。
答案 4 :(得分:1)
如果setName()
有关于如何设置名称的内在逻辑,那么我会选择2.另一方面,如果setName()
包含一些需要在名称时运行的附加代码设置,我会选择1。
让我做一些更复杂的情况,以便表达我的观点:
class Person {
private String firstName;
private String lastName;
private boolean wasRenamed;
//getters...
public Person(String fullName) {
???
}
public void setFullName(String fullName) {
???
}
}
这里我们有Person
个名字和姓氏,我们也希望记录谁重命名,谁不记录。让我们说fullName
包含以空格分隔的名和姓。现在让我们看一下您在问题中提供的两种不同方法:
setFullName()
:这将导致代码重复(按空格分割fullName
并将其分配给姓氏。setFullName()
:这会增加wasRenamed
标志的额外麻烦,因为setFullName()
必须设置此标志。 (这可以通过在调用false
之后简单地将标志重置回构造函数中的setFullName()
来解决,但是让我们说我们不想这样做)所以我会使用 1和2的组合,并拆分设置名称的内部逻辑和在名称设置为不同方法之前/之后需要运行的其他代码: / p>
class Person {
private String firstName;
private String lastName;
private boolean wasRenamed;
//getters...
private void setFullName0(String fullName) {
//split by space and set fields, don't touch wasRenamed flag
}
public Person(String fullName) {
setFullName0(fullName);
}
public void setFullName(String fullName) {
setFullName0(fullName);
wasRenamed = true;
}
}