我会开始道歉,因为我确信这已经在其他地方得到了解答 - 我找不到以我理解的方式解释它的答案!我正在做一个MSc转换课程,有一些基本的基础知识,我仍然在努力解决这个问题,包括这一个 - 为什么变量私有更好。
假设我有一个名为Person的Java类,带有print方法。我可以创建它并将其定义为:
public class Person
{
public String name;
public String telephoneNumber;
public void print()
{
System.out.println(name + " " + telephoneNumber);
}
}
然后,在主类中,我可以编写以下代码:
class testPerson
{
public static void main(String[] args)
{
Person test;
test = new Person();
test.name = "Mary";
test.telephoneNumber = "01234 567890";
test.print();
}
}
如果我这样做,test.print();会产生输出:
mary 01234 567890
但是,我知道这被认为编码不好。变量应该在公共类中是私有的,因为我们不希望人们看到这些信息的存储方式或者能够在未经授权的情况下编辑信息。
现在,我将编辑Person类以声明两个字符串私有并添加get和set方法,如下所示:
private String name;
private String telephoneNumber;
public void setName (String name)
{
this.name = name;
}
public void getName()
{
return name;
}
// same code for telephone methods.
现在,在主课程中,我会将设置姓名和电话的方法更改为以下内容:
mary.setName("Mary");
mary.settelephoneNumber("01234 567890");
根据我正在关注的讲义,这更有效(尽管可以通过添加Person()方法来实现更高效,以允许实例化等。)
但是,我很难理解这为何更好 在以前的处理方法中,用户可以直接访问变量。但即使通过隐藏变量而无法直接访问它们,用户也可以间接访问和修改它们,从而产生完全相同的结果。
为什么这是首选,毫无疑问,我错过/忽视了什么?
答案 0 :(得分:30)
比萨饼送货类比
了解Information Hiding和Encapsulation is not information hiding。
答案 1 :(得分:14)
并不是说它更有效率,而是它更易于维护和良好的实践。
例如,使用setter方法,您可以让setTelephoneNumber
实际检查String
是否是有效的电话号码,然后再进行设置。如果你把变量公之于众,你就不可能这样做。从一开始就使用setter意味着你可以回去,例如稍后再添加验证,如果您已将变量设置为public,则必须添加setter并修改所有用户以使用setter而不是直接修改变量。
答案 2 :(得分:4)
人们会给你一百万个反刍的原因,为什么它会更好,但只有在一些的情况下才会更好,而不是在所有情况下都是明确的。例如,使用Java自己的类GridBagConstraints
- 它根本没有任何方法(如果你不计算clone
,它还有它;所有Java类都继承它Object
)。为什么?因为有一种情况实际上更实用。 GridBagConstraints
是纯粹意义上的Java Bean:它完全是属性,没有业务逻辑。
让我从实践中报告另一个事实:没有任何人能够验证其输入;没有getter会计算出它的结果。在JavaBeans的世界中,任何这样的行为很快就会妨碍 setter设置和getter获取的普遍假设。基本上,如果你以任何方式偏离公共领域的确切等价物,你就输了。
现代Java API,如Hibernate,通过使用JavaBean样式属性在平等的基础上接受裸露的公共字段来承认这一事实。早期版本不允许这样做,但随着Java经验的积累,实现终于明白公共字段是正确的。
答案 3 :(得分:2)
你必须假设,在某些时候,其他人会使用你的代码 - 并且其他人可能是你,一年之后。如果你在一个类上看到一个公共财产,你应该能够假设你可以自由操纵它,如果它不能被直接修改你就不应该在外部看到它。
一个好的文字示例是位图对象的维度。如果你试图绘制尺寸为-10x-10的位图,大多数机器都不会喜欢它,因为这样的东西显然不可能在屏幕上表示。如果这个位图的宽度/高度属性只是公共变量,那么它们可能会被一个善意的编码器设置为无效值(从不认为它不会发生),并且当它呈现它时 - 砰,你有一台冷冻电脑。
通过隐藏变量并使用setter,您可以防止这种情况发生:
private int _width = 10;
public void setWidth(int value)
{
//Prevent the value moving into invalid range:
if(value < 1)
value = 1;
if(value > 4096)
value = 4096;
//Now apply it
_width = value;
}
但是,为了提高速度和方便性,您不必首先开发这样的代码 - 只需确保之后再进行操作并隐藏您需要的内容!
答案 4 :(得分:0)
还有一些安全问题需要考虑。一个常见的例子是银行账户。你有一个余额,你用存款来存钱,并提取以取消资金。如果余额是公开的,可以在不存入或取出资金的情况下进行修改。这可能非常糟糕。
在方法中,您可以对事物进行检查,例如确保您不会从帐户中获得比实际存在更多的钱。如果你直接访问这些值,你就无法真正做到这一点。这是关于控制的。