使用私人关键字

时间:2010-06-02 03:26:41

标签: java oop visibility

我是编程新手。我现在正在学习Java,有些东西我不太确定,那就是使用私有。为什么程序员将变量设置为私有,然后将write,getter和setter设置为访问它。无论如何,为什么不把所有东西都公之于众。

public class BadOO {
    public int size;

    public int weight;
    ...
}

public class ExploitBadOO {
    public static void main (String [] args) {
        BadOO b = new BadOO();
        b.size = -5; // Legal but bad!!
    }
}

我发现了一些像这样的代码,我看到评论合法但不好。我不明白为什么,请解释一下。

12 个答案:

答案 0 :(得分:22)

最重要的原因是隐藏班级的内部实施细节。如果您阻止程序员依赖这些细节,您可以安全地修改实现,而不必担心您将破坏使用该类的现有代码。

因此,通过将字段声明为私有,可以防止用户直接访问该变量。通过提供gettters和setter,您可以精确控制用户如何控制变量。

答案 1 :(得分:17)

不仅仅是将变量公之于众的主要原因是,如果你确实将其变为公开,那么你以后会产生更多的麻烦。

例如,一个程序员围绕私有成员变量编写公共getter和setter。三个月后,他需要验证变量永远不会“设置”为null。他在“setFoo(...)”方法中添加了一个检查,然后检查所有设置变量的尝试是否“将其设置为null”。案件结束,并且不费吹灰之力。

另一个程序员意识到,围绕私有成员变量放入公共getter和setter违反了封装精神,他认为方法是徒劳的,并决定公开成员变量。也许这会获得一点性能提升,或者程序员可能只是想“按照它的使用来编写它”。三个月后,他需要验证变量永远不会“设置”为null。他扫描对变量的每次访问,有效地搜索整个代码库,包括可能通过反射访问变量的所有代码。这包括已扩展其代码的所有第三方库,以及在编写后使用其代码的所有新编写的模块。然后,他修改所有调用以保证变量永远不会设置为null。案件永远不会关闭,因为他无法有效地找到对公开成员的所有访问,也无法访问所有第三方源代码。由于对新编写的模块缺乏了解,调查保证不完整。最后,他无法控制可能访问公共成员的未来代码,并且该代码可能包含将成员变量设置为null的行。

当然,第二个程序员可以通过在变量周围放置“get”和“set”方法并将其设置为私有来破坏所有现有代码,但是嘿,他可以在三个月前完成这个并保存自己解释为什么他需要打破其他人的代码。

按照你的意愿调用它,但是在私有成员变量周围设置公共“获取”和“设置”方法是防御性编程,这是多年(即数十年)经验带来的。

答案 2 :(得分:6)

班上任何公开的人都是与班级用户签订的合同。在修改类时,必须维护合同。您可以添加到合同(新方法,变量等),但不能从中删除。理想的是,您希望合同尽可能小。让一切都变得私密是很有用的。如果您需要从包成员直接访问,请将其保护。只将这些内容公之于众。

公开变量意味着您将永远签约,拥有该变量并允许用户修改它。如上所述,您可能会发现在访问变量时需要调用行为。如果您只收缩getter和setter方法,则可以这样做。

许多早期Java类都有合同要求它们是线程安全的。在只有一个线程可以访问实例的情况下,这会增加大量开销。较新的版本具有复制或增强功能但删除同步的新类。因此添加了StringBuilder,并且在大多数情况下应该使用StringBuilder而不是StringBuffer。

答案 3 :(得分:4)

它被认为是不好的主要是因为你无法控制谁可以改变价值以及价值变化时会发生什么。

在您为您编写的小应用程序中,它似乎并不那么重要,但是当您开始为越来越大的应用程序开发时,可以控制谁更改什么以及何时变得至关重要。

想象一下,根据上面的示例,您按原样发布库,其他人使用它,然后您决定在大小更改时计算坏类中的另一个值...突然bad00类无法知道和你无法改变它,因为其他人依赖它。

相反,如果你有一个set方法,你可以将它扩展为

void SetSize(int newSize)
{ 
   size = newSize;
   DoCalculation;
}

您可以扩展功能,而不会让其他人依赖您。

答案 4 :(得分:2)

我强烈推荐这本书Effective Java,它包含了很多关于如何用Java编写更好的程序的有用信息。

你的问题在该书的第13和14项中得到解决:

  • 第13项:尽量减少班级和成员的可访问性
  • 第14项:在公共类中,使用访问器方法,而不是公共字段

答案 5 :(得分:1)

您不应该允许实现直接更改您的记录。提供getter和setter意味着您可以精确控制变量的分配方式或返回的内容等。构造函数中的代码也是如此。如果在为大小分配值时,setter会执行一些特殊操作,该怎么办?如果直接指定它,就不会发生这种情况。

答案 6 :(得分:1)

这是许多程序员常见的烦恼 - 带有private字段和public访问者和变异器的Java代码。正如您所说,效果可能是public

还有一些编程语言可以为另一个极端发声。看看Python;在某种程度上,一切都是公开的。

这些是不同的编码实践,也是程序员每天都要处理的常见问题。但在Java中,这是我的经验法则:

  • 如果该字段纯粹用作属性,可由任何人阅读和编写,请将其设为 public
  • 如果该字段仅在内部使用,请使用 private 。如果您想要读取权限,请提供getter,如果您想要写入权限,请提供setter
  • 有一种特殊情况:有时,您希望在访问属性时处理额外数据。在这种情况下,您将同时提供getter和setter,但在这些属性函数中,您将做的不仅仅是return - 例如,如果您想跟踪其他程序读取属性的次数物体的生命时间。

这只是访问级别的简要概述。如果您有兴趣,请阅读protected访问权限。

答案 7 :(得分:1)

这确实用于隐藏内部实现。这也有助于为变量提供额外的逻辑。假设您需要确保为varable传递的值不应为0 / null,您可以在set方法中提供此逻辑。同样,你可以在获取值时提供一些逻辑,比如说你有一个未初始化的对象变量并且你正在访问该对象,在这种情况下,你可以提供逻辑以对该对象进行null检查并始终返回对象

答案 8 :(得分:0)

C#程序员使用它同样多,或者比我在Java中看到的更频繁。 C#调用它的属性,在Java中它是accessors / mutators

对我来说,使用getter和setter方法来封装类是有意义的,这样任何类都不能更改另一个类的实例变量。

答案 9 :(得分:0)

好。我们在这里谈论对象。现实世界的对象。如果它们不是私有的,则允许您的班级用户进行更改。如果对于Circle类,并且对于Circle类的radius属性/属性,用户将值设置为“0”。半径为“0”的圆存在没有意义。如果你将属性设为私有并提供一个setter方法,并且在其中抛出异常/错误(指示用户)不允许创建一个radisu为'0'的Circle,则可以避免此类错误。基本上,你的类中创建的对象 - 意味着存在,因为你希望它们存在。这是实现它的方法之一。

答案 10 :(得分:0)

如前所述,将变量设为私有的原因是将其隐藏在外面。但是,如果你制作一个吸气剂和一个定位器,那么你也可以将变量本身公开。如果您发现自己后来处于错误选择的位置,那么您必须重构代码,使用公共变量来使用getter / setter,这可能不是问题。但是,如果您无法控制的其他代码根据您的代码启动,则可能会出现问题。然后这样的重构将打破其他代码。如果您从一开始就使用getter和setter,那么您将减少风险以换取一点努力。所以这取决于你的情况。

答案 11 :(得分:-4)

这取决于谁访问这些公共变量。最有可能的是,只有公司/团队内部的人才。然后,在必要时将它们重构为getter / setter是微不足道的。我说在这种情况下,最好将变量公之于众;除非你被迫遵循java bean约定。

如果您正在编写面向公众的框架或库,则不应公开变量。你以后不可能将它们变成getter / setter。

但第二种情况比第一种情况更罕见;人们在软件工程师面前应用了极其不合理的假设,就像他们不是在编写代码一样,而是将代码刻在一起。就好像整个世界都在观察你的代码 - 实际上,没有人会读你的代码,除了你自己