我是Java的新手,我正在学习封装,并看到了一个示例,其中实例变量在类中声明为私有。
http://www.tutorialspoint.com/java/java_encapsulation.htm
我有2个查询:
如果实例变量在Java中的类中声明为public,你能用一个例子解释一下会出现什么问题吗?
答案 0 :(得分:35)
实例变量是私有的,以强制这些类的用户使用方法来访问它们。 在大多数情况下,有普通的getter和setter,但也可以使用其他方法。
例如,使用方法可以限制对只读的访问,即如果没有setter,则可以读取但不写入字段。如果这个领域是公开的,那是不可能的。
此外,您可以为字段访问添加一些检查或转换,这对于公共字段的普通访问是不可能的。如果某个字段是公开的,并且您以后想要通过执行其他检查等的某种方法强制所有访问。您必须更改该字段的所有用法。如果您将其设为私有,则只需稍后更改访问方法即可。
如果phone
是私有的:
考虑这种情况:
class Address {
private String phone;
public void setPhone(String phone) {
this.phone = phone;
}
}
//access:
Address a = new Address();
a.setPhone("001-555-12345");
如果我们开始使用这样的类,之后需要对phoneNumber执行检查(例如,一些最小长度,仅限数字等),您只需要更改setter:
class Address {
private String phone;
public void setPhone(String phone) {
if( !isValid( phone) ) { //the checks are performed in the isValid(...) method
throw new IllegalArgumentException("please set a valid phone number");
}
this.phone = phone;
}
}
//access:
Address a = new Address();
a.setPhone("001-555-12345"); //access is the same
如果phone
是公开的:
有人可以像这样设置phone
而你无法做任何事情:
Address a = new Address();
a.phone="001-555-12345";
如果您现在想强制执行验证检查,则必须将其设为私有,并且编写上述行的人必须将第二行更改为:
a.setPhone("001-555-12345");
因此,您不能在不破坏其他代码的情况下添加检查(它将不再编译)。
此外,如果通过方法访问类的所有字段/属性,则保持访问一致,用户不必担心属性是存储(即是实例字段)还是计算(只有方法和没有实例字段)。
答案 1 :(得分:10)
他们不拥有是私有的 - 但他们应该是。字段是实现细节 - 因此您应该将其保密。如果您想允许用户获取或设置其值,您可以使用属性来执行此操作(获取和设置方法) - 这样可以安全地执行此操作(例如验证输入)并允许您更改实现细节(例如,将一些值委托给其他对象等)而不会失去向后兼容性。
答案 2 :(得分:7)
首先,并非所有实例变量都是私有的。其中一些是受保护的,仍然保留了封装。
封装的一般思想是类不应暴露其内部状态。它应该只用它来执行它的方法。原因是每个班级都有一个所谓的“国家空间”。也就是说,其字段的一组可能值。它可以控制它的状态空间,但如果它暴露它,其他人可能会把它置于无效状态。
例如,如果您有两个布尔字段,并且该类只能在3种情况下正常运行:[false,false],[false,true]和[true,false]。如果将字段设置为public,则另一个对象可以设置[true,true],不知道内部约束,并且调用原始对象的下一个方法将触发意外结果。
答案 3 :(得分:4)
将实例变量设为公共或私有是一种设计权衡 设计师在宣布课程时做出的。通过制作实例 变量public,你公开了类实现的细节, 从而提供更高的效率和简洁的表达 阻碍未来维护工作的可能费用。通过 隐藏一个类的内部实现的细节,你有 有可能在未来改变班级的实施 不破坏任何使用该类的代码。
答案 4 :(得分:2)
已经有几个回答者已经指出过,实例变量不一定是private
,但为了保持封装,它们通常至少不是public
。 / p>
我在(我认为)清洁代码中看到了一个例子,它很好地说明了这一点。如果我没记错的话,这是一个复数(如a+bi
)类型;在任何情况下,非常类似的东西,我没有这本书方便。它暴露了获取实部和虚部的值的方法以及设置实例值的方法。这样做的最大好处是它允许在不破坏任何代码消费者的情况下完全替换实现。例如,复数可以存储在两种形式中的一种上:作为复平面上的坐标(a+bi
),或以极坐标形式(φ
和|z|
)。保持内部存储格式的实现细节允许您在仍然暴露两个表单上的数字时来回切换,从而让该类用户选择更方便他们当前正在执行的操作。
在其他情况下,如果字段x
落在给定范围内,则可能有一组相关字段,例如字段y
必须具有某些属性。一个简单的例子是x
必须在y
到y+z
的范围内,对于数值和一些任意值z
。通过公开访问器和更改器,您可以在两个值之间强制执行此关系;如果直接暴露实例变量,则不变量会立即崩溃,因为您无法保证某人不会设置一个而不会设置另一个,或者设置它们以使不变量不再成立。
当然,考虑到反思,仍然可以访问您不应该访问的成员,但如果有人反映您的班级访问私人成员,他们最好意识到他们正在做的事情可能会破坏事情。如果他们使用公共界面,他们可能认为一切都很好,然后他们最终会遇到令人讨厌的错误,因为他们在不知不觉中没有完全遵守您特定实现的实现细节。
答案 5 :(得分:1)
在传统的面向对象设计中,类将封装数据(变量)和行为(方法)。拥有私有数据将为您提供关于如何实现行为的灵活性,因此,例如,对象可以存储值列表并具有计算并返回这些值的平均值的getAverage()方法。稍后,您可以优化并缓存类中的计算平均值,但合同(即方法)不需要更改。
过去几年(无论好坏)使用anemic data models变得越来越流行,其中一个类只不过是一堆字段和相应的getter和setter。我认为在这个设计中你会更好地使用公共领域,因为getter和setter没有提供真正的封装,但只是愚弄你以为你在做真正的OO。
更新:问题中链接中给出的示例是这种简并封装的完美示例。我意识到作者试图提供一个简单的例子,但是这样做无法传达封装的任何实际好处(至少在示例代码中没有)。
答案 6 :(得分:0)
因为如果你改变了类的结构(删除字段等);它会导致错误。但是如果你有一个getX()
方法,你可以在那里计算所需的值(如果删除了字段)。
您遇到的问题是,该课程不知道某些内容是否有所改变且无法保证完整性。
答案 7 :(得分:0)
如上所述,保持良好的领域具有许多优点。 下一个最佳级别是使用java默认访问级别将它们保密。
默认级别可以避免在您自己的代码中出现混乱,并防止您的代码客户端设置无效值。
答案 8 :(得分:0)
我们正在使用像eclipse,netbins这样的ide ..... 看到它建议我们使用公共方法,所以如果类的创建者为私有实例变量提供getter和setter,则不必记住变量的名称。只需编写set press ctrl + space,即可获得该类创建者创建的所有setter方法,并选择所需的方法来设置变量值。
有时您需要指定一些逻辑来设置变量值。 "假设你有一个应该存储0的整数变量