2010-06-02 73 views
20

我是编程新手。我现在正在学习Java,有一些我不太确定,即使用私有。为什么程序员将变量设置为私有,然后写入,获取器和设置器来访问它。无论如何,为什么不把所有东西都公开呢?使用私人关键字

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!! 
    } 
} 

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

回答

17

不只是首先让公众参与变量的主要原因是,如果您确实公开了这个变量,那么您将在稍后创建更多令人头疼的问题。

例如,一位程序员围绕私有成员变量编写公共getter和setter。三个月后,他需要验证变量是否从未“设置”为空。他在“setFoo(...)”方法中添加了一个检查,然后检查所有设置该变量的尝试是否将它设置为null。案件结案,并没有多少努力。另一位程序员意识到,将私有成员变量放在公共getter和setter中违反了封装的精神,他认为这些方法是徒劳的,并决定只是将成员变量公开。也许这会带来一些性能提升,或者程序员可能只是“随着它的使用而写”。三个月后,他需要验证变量是否从未“设置”为空。他扫描对变量的所有访问,有效搜索整个代码库,包括可能通过反射访问变量的所有代码。这包括所有扩展了他的代码的第三方库,以及所有新编写的模块,这些模块在编写后使用了他的代码。然后,他会修改所有调用以确保该变量从不设置为空。该案件从未关闭,因为他无法有效地查找所有暴露的成员,也无法访问所有第三方源代码。由于对新编写模块的了解不完善,调查保证不完整。最后,他无法控制将来访问公共成员的代码,并且该代码可能包含将成员变量设置为空的行。

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

打电话给你,但将私人成员变量中的公开“get”和“set”方法放在一个多年(即数十年)经验带来的防御性编程中。

+0

它也使得调试更容易,因为你可以在你的getter和setter中添加日志记录或断点或其他任何东西。 – Brian 2010-10-19 21:16:54

22

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

所以通过声明外地私人您防止用户直接访问变量。通过提供gettters和setter,您可以精确控制用户如何控制变量。

+4

+1对于在提问者提供的答案为 – Catchwa 2010-06-02 04:47:45

1

你不应该让实现直接改变你的记录。提供getters和setter意味着您可以精确控制变量如何分配或返回什么等。同样的事情适用于构造函数中的代码。如果设定者在将值分配给大小时做了特别的事情会怎么样?如果您直接分配它,这不会发生。

1

这是许多程序员的常见宠物 - Java代码private字段和public访问器和增变器。效果如你所说,这些字段可能是public

也有编程语言的声音,另一个极端。看看Python;几乎所有事情都是公开的,在一定程度上。

这些都是不同的编码做法和常见的事程序员每天处理。但在Java中,这是我的经验之谈:

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

这只是在访问级别的简要概述。如果你有兴趣,也可以阅读protected访问。

+1

的适当级别“如果该字段纯粹作为属性使用,任何人都可读和可写,则将其公开。”完全不同意;一旦你做了一个现场发布忘记了改变我。 X – Pierreten 2010-06-02 04:03:08

+0

更改I.X?无论如何,这种做法是语言依赖的,欢迎您不同意。 – 2010-06-02 04:45:55

+1

只要明确了它们的使用方式,公共属性就没有任何问题。在Java中它不会发生太多,但其他语言的意见稍有不同。 C#很好,因为您可以稍后使用相同的名称将属性更改为get(/ set)对。 – 2010-06-02 14:03:05

4

它认为是不好的,主要是因为你对谁可以更改值失去控制会发生什么变化值时。

在用你为你而写的小应用程序也不会显得那么重要,但是当你开始对越来越大的应用开发具有了谁改变了什么,什么时候成为关键控制。

想象一下,从你上面的例子,你发布图书馆,其他人使用它,然后你决定你想在你的坏班级中计算另一个值,当大小发生变化时......突然bad00类没有办法知道你不能改变它,因为其他人依赖它。

相反,如果你有,你可以扩展它说

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

你可以不上你打破其他国家人民的信任扩展功能的一组方法。

0

C#程序员同样使用它,或者比我在Java中看到的更频繁。 C#将其称为Java属性,它是访问器/增变器

对我来说,有getter和setter方法来封装类是有意义的,以便没有类可以更改另一个类的实例变量。

+2

C#对属性有真正的支持,并且支持统一访问原则http://en.wikipedia.org/wiki/Uniform_access_principle,这使得使用属性比使用Java更简单。 – Jesper 2010-06-02 07:18:37

+0

谢谢文章Jesper;在使用属性时,我始终牢记这一概念,但现在有一个标签。 – Pierreten 2010-06-02 15:27:24

5

你班上的任何公开内容都是与班上的用户签订的合同。在您修改班级时,您必须维护合同。您可以添加到合同(新方法,变量等),但无法从中删除。理想情况下,你希望合同尽可能小。将所有东西都变为私有是很有用的。如果您需要包成员的直接访问权限,请将其保护起来。只将你的用户需要的东西公开。

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

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

-4

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

如果你正在为公众编写一个框架或库,那么你不应该暴露变量。你以后不可能将它们改成getter/setter。

但是第二种情况比第一种更罕见;当软件工程师遇到软件工程师时,人们会应用极其不合理的假设,就好像他们不是在编写代码一样,而是在刻意制作代码。而且仿佛整个世界都在注视着你的代码 - 实际上,除了你自己,没有人会读你的代码

+1

不同意。如果你在一个合适的团队中工作,你的代码不只是自己阅读。你有没有尝试同行评审和配对编程? – 2010-06-02 05:13:47

+3

我不知道你有多少现实世界的软件开发经验,不值得信赖;但就像一个轶事一样,我现在不得不为6年前由开发人员编写的代码添加新功能,这些开发人员显然有自己的想法。您的代码在生产中将会拥有自己的一生。 – Pierreten 2010-06-02 15:30:45

1

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

2

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

你的问题在项目13和这本书的14解决:

  • 项目13:尽量减少类和成员
  • 14项辅助功能:在公共类,使用存取方法,而不是公共领域
0

好的。我们在这里讨论Objects。真实世界的对象。如果他们不是私人的,你的班级的用户可以改变。如果对于Circle类以及Circle类的radius属性/属性,用户将值设置为“0”。圆形与半径存在为'0'是没有意义的。如果你的属性是私有的并且给定一个setter方法,并且抛出异常/错误(指示用户)不允许用radisu创建一个为'0'的圆,你可以避免这样的错误。基本上,创建在你的课堂之外的对象 - 就是要存在,因为你希望它们存在。这是实现它的途径之一。

0

如前所述,制作一个可变私人的原因是将其隐藏起来。但是如果你让一个getter和一个setter,那么你也可以让变量本身公开。如果你后来发现自己做出了错误的选择,那么你必须使用public变量重构你的代码来使用getter/setter,这可能不是问题。但是,如果其他代码不受您的控制,则会根据您的代码启动。那么这样的重构会破坏其他代码。如果你从一开始就使用getter和setter,你会减少这个风险,换来一点点努力。所以这取决于你的情况。