如果“更安全”应该是指安全性,那么这不是真的。有很多方法可以访问对象的私有变量。
如果“更安全”是指健壮代码,即不太可能发生异常或无法正常工作的代码,那么是的,它更安全。好处是您的班级可以完全控制价值。
最简单的例子是空值。考虑这个类:
public class Person {
public String firstName;
public String lastName;
public List<Person> relatives;
}
如果我想编写一个接受 Person 实例的方法,我无法保证字段不为空。我必须用检查来弄乱我的代码:
void populateFieldsWith(Person person) {
firstNameField.setText(person.firstName != null ? person.firstName : "");
lastNameField.setText(person.lastName != null ? person.lastName : "");
if (person.relatives != null) {
List<String> names = new ArrayList<>();
for (Person relative : person.relatives) {
if (relative != null
&& relative.firstName != null
&& relative.lastName != null) {
names.add(relative.firstName + " " + relative.lastName);
}
}
nameList.setData(names);
} else {
nameList.setData(Collections.emptyList());
}
}
如果字段是私有的,那么 Person 类是唯一可以修改它们的类,这使 Person 类能够确保它们不为空:
public class Person {
private String firstName;
private String lastName;
private final List<Person> relatives = new ArrayList<>();
/**
* Creates a new Person instance.
*
* @param firstName person's first name; cannot be null
* @param lastName person's last name; cannot be null
*
* @throws RuntimeException if any argument is null
*/
public Person(String firstName,
String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
/**
* Returns this person's first name. This never returns null.
*/
public String getFirstName() {
return firstName;
}
/**
* Sets this person's first name.
*
* @param name new non-null first name
*
* @throws RuntimeException if any argument is null
*/
public void setFirstName(String name) {
Objects.requireNonNull(name, "Name cannot be null");
this.firstName = name;
}
/**
* Returns this person's last name. This never returns null.
*/
public String getLastName() {
return lastName;
}
/**
* Sets this person's last name.
*
* @param name new non-null last name
*
* @throws RuntimeException if any argument is null
*/
public void setLastName(String name) {
Objects.requireNonNull(name, "Name cannot be null");
this.lastName = name;
}
/**
* Returns a list of this person's relatives. This never returns null
* but it may return an empty list.
*/
public List<Person> getRelatives() {
return new ArrayList<Person>(relatives);
}
public void setRelatives(List<Person> relatives) {
Objects.requireNonNull(relatives, "List cannot be null");
for (Person person : relatives) {
Objects.requireNonNull(person, "List cannot contain null");
}
this.relatives.clear();
this.relatives.addAll(relatives);
}
public void addRelative(Person relative) {
Objects.requireNonNull(relative, "Person cannot be null");
this.relatives.add(relative);
}
}
现在我们有了一个牢不可破的类(除非有人使用反射来绕过私有访问,但在这种情况下,您正在处理恶意代码并且进入完全不同的运行时主题安全)。
firstName 永远不可能为 null,因为任何外部代码可以设置它的唯一方法是通过 setFirstName 方法,并且该方法不允许将字段设置为 null价值。
现在,让我们回到想要使用 Person 实例的代码:
void populateFieldsWith(Person person) {
firstNameField.setText(person.getFirstName());
lastNameField.setText(person.getLastName());
List<String> names = new ArrayList<>();
for (Person relative : person.getRelatives()) {
names.add(relative.getFirstName() + " " + relative.getLastName());
}
nameList.setData(names);
}
该方法不再需要检查是否为空。程序员可以放心地假定该值不为空,因为 javadoc 保证了这一点。保证是诚实的,因为没有可以导致方法返回 null 的代码路径。
空值只是一种用途。同样的setFirstName 方法还可以检查字符串是否为非空,检查它是否不超过最大长度,检查它是否只包含某些类型的字符,等等,所有这些,所以getFirstName 方法可以通过其 javadoc 向其他程序员保证它将返回有效数据。