使用私人关键字

我是编程新手。 我现在正在学习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!! } } 

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

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

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

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

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

把它称之为你想要的,但是在私有成员变量周围设置公共“获取”和“设置”方法是防御性编程,这是多年(即数十年)经验带来的。

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

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

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

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

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

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

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

想象一下,从上面的例子中,你按原样发布库,其他人使用它,然后当你的大小发生变化时,你决定要在你的坏类中计算另一个值…突然bad00类无法知道你可以’改变它,因为其他人依赖它。

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

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

您可以扩展function,而不会破坏其他人对您的依赖。

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

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

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

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

这是许多程序员的常见宠儿 – 具有private字段和public访问者和变异器的Java代码。 正如你所说的那样,这些领域可能也是public

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

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

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

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

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

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

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

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

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

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

如果您正在编写面向公众的框架或库,则不应公开变量。 您以后无法将它们更改为getter / setter。

但第二种情况比第一种情况更罕见; 当人们向软件工程师提出非常不合理的假设时,就好像他们不是在编写代码一样,而是将代码刻在一起。 就好像整个世界都在观察你的代码 – 实际上, 除了你自己以外没有人会读过你的代码