为什么Java中的实例变量总是私有的?
我是 Java 新手,正在学习封装,并看到了一个实例变量在类中声明为私有的示例。
http://www.tutorialspoint.com/java/java_encapsulation.htm
我有 2 个查询:
- 为什么实例变量是私有的?为什么不公开?
- 如果实例变量公开并直接访问怎么办?我们看到任何限制吗?
你能用一个例子解释一下如果在 Java 的类中将实例变量声明为 public 会出现什么问题吗?
I'm newbie to Java and I'm learning about encapsulation and saw an example where instance variables are declared as private in a class.
http://www.tutorialspoint.com/java/java_encapsulation.htm
I have 2 queries:
- Why are instance variables private? Why not public?
- What if instance variables are made public and accessed directly? Do we see any constraints?
Can you explain with an example as to what will go wrong in case the instance variables are declared as public in a class in Java?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
实例变量被设为私有,以强制这些类的用户使用方法来访问它们。
在大多数情况下,有简单的 getter 和 setter,但也可以使用其他方法。
例如,使用方法可以将访问限制为只读,即如果没有设置器,则可以读取字段但不能写入字段。如果该领域是公开的,这是不可能的。
此外,您可以为字段访问添加一些检查或转换,这对于公共字段的普通访问是不可能的。如果某个字段是公共的,并且您稍后希望通过某种执行附加检查等的方法强制所有访问,则必须更改该字段的所有用法。如果将其设为私有,则只需稍后更改访问方法即可。
如果
phone
是私有的:考虑这种情况:
如果我们从这样的类开始,然后需要对phoneNumber执行检查(例如一些最小长度,数字仅等)您只需更改设置器:
如果
phone
是公开的:有人可以像这样设置
phone
而您不能采取任何措施:如果您现在想要强制执行验证检查您必须将其设为私有,并且无论谁编写了上述行,都必须将第二行更改为:
因此,您不能在不破坏其他代码的情况下添加检查(它将不再编译)。
此外,如果您通过方法访问类的所有字段/属性,则可以保持访问一致,并且用户不必担心该属性是存储的(即实例字段)还是计算的(只有方法而没有实例字段) )。
Instance variables are made private to force the users of those class to use methods to access them.
In most cases there are plain getters and setters but other methods might be used as well.
Using methods would allow you, for instance, to restrict access to read only, i.e. a field might be read but not written, if there's no setter. That would not be possible if the field was public.
Additionally, you might add some checks or conversions for the field access, which would not be possible with plain access to a public field. If a field was public and you'd later like to force all access through some method that performs additional checks etc. You'd have to change all usages of that field. If you make it private, you'd just have to change the access methods later on.
If
phone
was private:Consider this case:
If we started with the class like this and later it would be required to perform checks on the phoneNumber (e.g. some minimum length, digits only etc.) you'd just have to change the setter:
If
phone
was public:Someone could set
phone
like this and you could not do anything about it:If you now want to force the validation checks to be performed you'd have to make it private and whoever wrote the above lines would have to change the second line to this:
Thus you couldn't just add the checks without breaking other code (it wouldn't compile anymore).
Additionally, if you access all fields/properties of a class through methods you keep access consistent and the user would not have to worry about whether the property is stored (i.e. is a instance field) or calculated (there are just methods and no instance fields).
它们不一定是私有的,但它们应该是私有的。字段是一个实现细节 - 因此您应该将其保持私有。如果您想允许用户获取或设置其值,您可以使用属性来执行此操作(获取和设置方法) - 这可以让您安全地执行此操作(例如验证输入)并且还允许您更改实现细节(例如,将一些值委托给其他对象等)而不失去向后兼容性。
They don't have to be private - but they should be. A field is an implementation detail - so you should keep it private. If you want to allow users to fetch or set its value, you use properties to do so (get and set methods) - this lets you do it safely (e.g. validating input) and also allows you to change the implementation details (e.g. to delegate some of the values to other objects etc) without losing backward compatibility.
首先,并非所有实例变量都是私有的。其中一些受到保护,仍然保留了封装性。
封装的总体思想是类不应该暴露其内部状态。它应该只使用它来执行它的方法。原因是每个类都有一个所谓的“状态空间”。即,其字段的一组可能值。它可以控制其状态空间,但如果它公开它,其他人可能会将其置于无效状态。
例如,如果您有两个布尔字段,并且该类仅在 3 种情况下才能正常运行:[false, false]、[false, true] 和 [true, false]。如果将字段设为公共,则另一个对象可以在不知道内部约束的情况下设置 [true, true],并且在原始对象上调用的 next 方法将触发意外结果。
First, it is not true that all instance variables are private. Some of them are protected, which still preserves encapsulation.
The general idea of encapsulation is that a class should not expose its internal state. It should only use it for performing its methods. The reason is that each class has a so-called "state space". That is, a set of possible values for its fields. It can control its state space, but if it exposes it, others might put it in an invalid state.
For example, if you have two boolean fields, and the class can function properly only in 3 cases: [false, false], [false, true], and [true, false]. If you make the fields public, another object can set [true, true], not knowing the internal constraints, and the next method called on the original object will trigger unexpected results.
Oracle 白皮书
Oracle White Paper
就像几个回答者已经指出的那样,实例变量不必是
private
,但它们通常至少不设为public
,以便保留封装。我在(我认为)《清洁代码》中看到了一个例子,它很好地说明了这一点。如果我没记错的话,它是一个复数(如
a+bi
)类型;无论如何,非常类似的事情,我手边没有这本书。它公开了获取实部和虚部值的方法以及设置实例值的方法。这样做的最大好处是,它允许完全替换实现,而不会破坏代码的任何使用者。例如,复数可以以两种形式之一存储:作为复平面上的坐标 (a+bi
),或以极坐标形式(φ
和|z|
)。将内部存储格式保留为实现细节允许您来回更改,同时仍然在两种形式上公开数字,从而让类的用户选择对他们当前正在执行的操作更方便的方式。在其他情况下,您可能有一组相关字段,例如如果字段
y
落在给定范围内,则字段x
必须具有某些属性。一个简单的例子是,对于数值和某个任意值z,
。通过公开访问器和修改器,您可以强制两个值之间的这种关系;如果您直接公开实例变量,则不变量会立即崩溃,因为您无法保证某人不会设置一个而不是另一个,或者设置它们以使不变量不再成立。x
必须在y
到y+z
范围内当然,考虑到反射,仍然有可能访问您不应该访问的成员,但是如果有人反映您的类来访问私有成员,他们最好意识到他们所做的事情很可能会破坏事情。如果他们使用公共接口,他们可能会认为一切都很好,然后他们最终会遇到令人讨厌的错误,因为他们在不知不觉中没有完全遵守特定实现的实现细节。
Like has been pointed out by several answerers already, instance variables don't have to be
private
, but they are usually at the very least not madepublic
, in order to preserve encapsulation.I saw an example in (I think) Clean Code, which very well illustrates this. If I recall correctly, it was a complex number (as in
a+bi
) type; in any case, something very much like that, I don't have the book handy. It exposed methods to get the value of the real and imaginary parts as well as a method to set the value of the instance. The big benefit of this is that it allows the implementation to be completely replaced without breaking any consumers of the code. For example, complex numbers can be stored on one of two forms: as coordinates on the complex plane (a+bi
), or in polar form (φ
and|z|
). Keeping the internal storage format an implementation detail allows you to change back and forth while still exposing the number on both forms, thus letting the user of the class pick whichever is more convenient for the operation they are currently performing.In other situations, you may have a set of related fields, such as field
x
must have certain properties if fieldy
falls inside a given range. A simplistic example would be wherex
must be in the rangey
throughy+z
, for numerical values and some arbitrary valuez
. By exposing accessors and mutators, you can enforce this relationship between the two values; if you expose the instance variables directly, the invariant falls apart immediately, since you cannot guarantee that someone won't set one but not the other, or set them so that the invariant no longer holds.Of course, considering reflection, it's still possible to access members you aren't supposed to, but if someone is reflecting your class to access private members, they had better realize that what they are doing may very well break things. If they are using the public interface, they might think everything is fine, and then they end up with nasty bugs because they unknowingly did not fully adhere to the implementation details of your particular implementation.
在传统的面向对象设计中,类将封装数据(变量)和行为(方法)。拥有私有数据将为您提供如何实现行为的灵活性,例如,一个对象可以存储一个值列表,并具有一个 getAverage() 方法来计算并返回这些值的平均值。稍后,您可以在类中优化和缓存计算出的平均值,但契约(即方法)不需要更改。
在过去的几年里,使用贫血数据模型变得越来越流行(无论好坏),其中类只不过是一堆字段和相应的 getter 和 setter。我认为,在这种设计中,使用公共字段会更好,因为 getter 和 setter 没有提供真正的封装,而只是愚弄你,让你认为你正在做真正的面向对象。
更新:问题链接中给出的示例是这种退化封装的完美示例。我意识到作者试图提供一个简单的示例,但这样做未能传达封装的任何真正好处(至少在示例代码中没有)。
In traditional Object-Oriented design, a class will encapsulate both data (variables) and behavior (methods). Having private data will give you flexibility as to how the behavior is implemented, so for example, an object could store a list of values and have a getAverage() method that computes and returns the mean of these values. Later on, you could optimize and cache the computed average in the class, but the contract (i.e., the methods) would not need to change.
It has become more popular the past few years (for better or worse) to use anemic data models, where a class is nothing but a bunch of fields and corresponding getters and setters. I would argue that in this design you would be better off with public fields, since the getters and setters provide no real encapsulation, but just fool you into thinking you are doing real OO.
UPDATE: The example given in the link in the question is a perfect example of this degenerate encapsulation. I realize the author is trying to provide a simple example, but in doing so, fails to convey any real benefit of encapsulation (at least not in the example code).
因为如果您更改类的结构(删除字段等);它会导致错误。但是,如果您有一个 getX() 方法,您可以在那里计算所需的值(如果字段被删除)。
您遇到的问题是,该类不知道某些内容是否已更改,并且无法保证完整性。
Because if you change the structure of the class (removing fields etc.); it will cause bugs. But if you have a
getX()
method you can calculate the needed value there (if field was removed).You have the problem then that the class does not know if something is changed and can't guarantee integrity.
如上所述,保持字段私有有很多优点。
下一个最佳级别是使用 java 默认访问级别将它们保持为包私有。
默认级别可避免您自己的代码混乱,并防止代码的客户端设置无效值。
Well keeping fields private has many advantages as suggested above.
Next best level is to keep them package private using java default access level.
Default level avoid cluttering in your own code and prevents clients of your code from setting invalid values.
的 We 类用户
对于使用 eclipse、netbins 等 ide ......
看到它建议我们使用公共方法,因此如果类的创建者为私有实例变量提供 getter 和 setter,则您不必记住变量的名称。只需编写 set 按 ctrl+space 即可获取该类的创建者创建的所有 setter 方法,并选择所需的方法来设置变量值。
对于类的创建者
有时您需要指定一些逻辑来设置变量值。
“假设你有一个应该存储 0 的整数变量
For user of class
We, who are using ide like eclipse, netbins.....
saw that it suggest us for public method, so if creator of class provide getter and setter for private instance variable you do not have to memorize the name of variable. just write set press ctrl+space you are getting all of setter method created by creator of that class and choose your desired method to set your variable value.
For creator of class
Sometimes you need to specify some logic to set variable value.
"suppose you have an integer variable which should store 0