我听说直接使用类属性并不是一个好主意,而是使用setter和getter。有人可以告诉我为什么吗?
答案 0 :(得分:6)
有趣的是,关于这个主题的维基百科文章提供了很好的指导:http://en.wikipedia.org/wiki/Accessor
简而言之,类应该使用mutator方法(getter,setter等)在私有存储之前验证输入。这样做可确保始终可以依赖代码中的其他位置。
相比之下,如果属性是全球可用的,任何人都可以修改它。例如,如果您有一个需要特定格式的字符串,并且有人添加了一个不正确的值,则可能会导致错误。
答案 1 :(得分:5)
简而言之,如果您编写接口(包含getter和setter到私有字段)的代码,那么您可以换出符合该接口的任何对象。对象字段的外部引用意味着外部用户知道实现。这会在对象的使用者和对象的实现之间产生耦合,在这种情况下这是一件坏事。
今天您的name
字段可能会存储为String
,但明年您可能希望将其更新为某种更有趣的类型,或者从其他地方或任何其他地方获取信息......谁知道?使用字段会阻止您这样做。使用访问器可以让您根据需要更改实现。这是一个比你想象的更重要的原则。
您可能会感兴趣:[{3}}
答案 2 :(得分:1)
这取决于;对于类中的简单更改(bool成员),更改它可能更快。如果它稍微复杂一些(MyDate),那么你可能想要实现一些验证。
大多数人将成员数据保密,因此必须使用get / set或方法来修改类外的数据。
答案 3 :(得分:1)
这是一项惯例,虽然是强有力的。
JavaBean规范使用它来解决Java没有属性的问题。
它允许表达只读/只写或读写属性的意图。
在setter中放置断点以查看属性无法更改的原因非常方便。
如前所述,接口不能包含属性,但可以定义访问器。
有时你会想要创建'虚拟'属性,经典的例子是复数,你有属性x和y,并通过setter和getters中的计算提供mod和angle。
许多API依靠此约定通过反射推断出你的类的含义。
所有IDE现在都可以自动生成它们,这样它们就不会像过去那样伤害我的手指。
答案 4 :(得分:1)
有两个经典原因要禁止外部访问字段(属性)。这些通常在介绍性面向对象编程类中讨论。
答案 5 :(得分:1)
真正归结为Java不尊重Uniform Access Principle。也就是说,用于改变字段值的客户端代码(例如obj.field = newValue
)与用于调用setter的代码(例如obj.setField(newValue)
)非常不同。
如果您从公共字段开始,后来确定您确实需要私有成员(例如,添加验证或更改成员的基础实现),则所有客户端代码都将中断。因此,如果任何机会您需要访问者提供的其他功能,则需要使用setter而不是public字段。最终结果是许多不必要的代码:
public class Person {
private String _firstName;
private String _lastName;
public Person(String firstName, String lastName) {
_firstName = firstName;
_lastName = lastName;
}
public String getFirstName() {
return _firstName;
}
public void setFirstName(String name) {
_firstName = name;
}
public String getLastName() {
return _lastName;
}
public void setLastName(String name) {
_lastName = name;
}
}
在尊重UAP的语言中,例如Scala,使用公共字段而不是getter / setter是很常见的。例如,Scala中的上述类是:
class Person(var firstName: String, var lastName: String)
// example client code:
val p = new Person("John", "Smith");
p.lastName = "Brown";
如果我决定需要验证,我可以将其替换为:
class Person(firstName: String, lastName: String)
private var _firstName = validate(firstName);
private var _lastName = validate(lastName);
// getters
def firstName: String = _firstName
def lastName: String = _lastName
// setters
def firstName_=(name: String): Unit = {
_firstName = validate(name);
}
def lastName_=(name: String): Unit = {
_lastName = validate(name);
}
// validation
@throws(classOf[IllegalArgumentException])
private def validate(name: String): String = {
// ... validation code ...
name
}
}
// and client code doesn't break!
val p = new Person("John", "Smith");
p.lastName = "Brown";