当我能够使用setter方法更改属性值时,封装的用途是什么?
我尝试了很多次,但我没理解这一点。
封装是一种将类中的字段设为私有并通过公共方法提供对字段的访问的技术。 如果某个字段被声明为私有,则该类之外的任何人都无法访问该字段,从而将该字段隐藏在该类中。
我们如何通过setter方法更改字段的值? 我们如何防止直接访问这些字段? 封装的真正用途是什么?
假设您有age
属性。
用户可以输入值-10
,虽然这是有效数字,但是年龄无效。 setter方法可以有逻辑,允许你捕获这些东西。
另一种情况是拥有age
字段,但隐藏它。 你也可以有一个出生日期字段,在它的setter你会有这样的东西:
... private int age private Date dob ... public void setDateOfBirth(Date dob) { this.dob = dob; age = ... //some logic to calculate the age from the Date of Birth. }
在我阅读“面向对象编程语言中的封装和inheritance”一书以及解释封装重要性的网站之前,我也一直很困惑。 我实际上是从网站上导向了这本书。
人们总是说封装是“隐藏信息”,因此可能使封装集中在安全性上作为主要用途。 是的,你在实践中隐藏信息,但这不应该是定义,因为它可能会让人感到困惑。
封装只是“通过定义严格的外部接口来最小化单独编写的模块之间的相互依赖性”(引自本书)。 也就是说,当我构建一个模块时,我想要我的客户和我之间就如何访问我的模块签订严格的合同。 原因在于,我可以改善内部运作而不影响我的客户,生活,应用程序或他们使用我的模块的任何事情。 因为他们的“模块”并不完全取决于我的模块的内部工作,而是取决于“外部接口”,我向他们提供了。
因此,如果我没有为我的客户端提供一个setter并让他们直接访问变量,我意识到我需要在我的客户端使用它之前对变量设置一些限制,我改变它,可能是我,改变我客户的生命,或我的客户申请巨额费用。 但如果我通过创建一个“严格的外部接口”即setter来提供“严格的合同”,那么我可以很容易地改变我的内部工作,而不需要花费任何费用给我的客户。
在setter情况下(使用封装),如果发生在设置变量时,我返回一条消息通知您已经分配了,现在我可以通过我的“界面”发送消息,通知我的客户新的我的模块必须与之交互的方式,即“你不能分配负数”,即如果我的客户试图分配负数。 但是,如果我没有使用封装,并让我的客户端直接访问变量,我做了我的更改,它可能导致崩溃的系统,因为,如果我实施的限制,是,你,你无法保存负面和我的客户端我总是能够存储负面信息,我的客户手中会有一个崩溃的系统(如果那个“崩溃的系统”是一个银行系统,想象会发生什么)。
因此封装更多的是减少模块之间的依赖性,因此可以“安静地”进行改进,而与其交互的其他模块的费用很少或没有,而不是安全性。 因为交互模块依赖于“严格的外部接口或严格的合同”。
我希望这能解释得恰到好处。 如果没有,你可以去下面的链接自己阅读。
封装很重要
面向对象编程语言中的封装与inheritance
封装的真正用途还在于您可以对值的设置方式进行额外的检查/处理。
您并没有完全阻止对字段的访问 – 您正在控制其他人访问某些字段的方式。 例如,您可以向setter方法添加validation,或者也可以在调用字段的setter方法时更新其他一些依赖字段。
您可以阻止对该字段的写入或读取访问(例如,通过仅分别提供getter或setter) – 但是使用属性进行封装可以让您做更多的事情。
任何我如何能够通过setter方法更改字段的值。
只有setter方法允许你这样做。
我们如何阻止访问字段?
setter和getter控制是否以及如何访问字段。
设定者可以检查该值是否有效。 它可能会询问SecurityManager是否允许您这样做。 它可以在数据类型之间转换。 等等。
如果你有私有字段,他们不能在课外访问,这意味着基本上这些字段不存在于外部世界,是的你可以通过setter方法改变它们的值但是使用setter方法你有更多的灵活性/控制来说谁可以改变字段以及它们可以更改为什么值…基本上使用封装,您可以限制如何以及谁更改字段。 例如,你有:私人双薪,你的setter方法可以限制只有hr工作人员可以改变它可以写成的薪水字段:
void setSalary(Person p,double newSalary) { //only HR objects have access to change salary field. If(p instanceof HR && newSalary>=0) //change salary. else Sop("access denied"); }
想象一下,如果工资是公开的并且可以直接访问任何可以随时改变它,并且无论何时他们想要,这基本上是封装的重要性
它的目标只是保护易于改变的任何东西。 你在网上有很多例子,所以我给你一些优点:
- Encapsulated Code更灵活 ,更易于根据新要求进行更改
- 允许您控制谁可以访问什么 。 (!!!)
- 帮助在Java中编写
immutable class
- 它允许您更改代码的一部分而不影响代码的其他部分。
通过方法访问字段会产生差异,因为它会使其成为OOP。 例如,您可以扩展您的课程并更改您无法直接访问的行为。 如果你有getter / setter,你可以代理你的类,做一些AOP或做一个1.4动态代理。 你可以从你的class级做一个模拟并进行unit testing……
让我们假设您使用以下setter / getter创建自定义Date类:
getDay() getMonth() getYear() setDay() setMonth() setYear()
在内部,您可以使用以下方式存储日期:
private int day; private int month; private int year;
或者您可以使用java.lang.Date-object存储日期:
private Date date;
封装不会暴露您的类在内部的工作方式。 它让您更自由地改变课程的运作方式。 它使您可以选择控制对类的访问。 您可以检查用户输入的内容是否有效(您不希望用户输入值为32的日期)。
Encapsultaion用于隐藏成员变量,方法是将成员设置为私有,并通过getter和setter方法访问该成员变量。
例
class Encapsulation {
private int value ; Encapsulation() { System.out.println("constructor calling "); } void setValue(int value){ this.value = value; } int getValue() { return value; }
} class EncapsulationMain {
public static void main(String args[]) { Encapsulation obj = new Encapsulation(); obj.setValue(4); //System.out.print("value is "+obj.value); //obj.value = 55; //System.out.print("obj changing the value"+obj.value); System.out.print("calling the value through the getterMethod"+obj.getValue()); }
}
你不能访问课外的私人价值。
那么,封装并不是关于隐藏数据的全部内容。 这一切都是为了控制存储在字段中的内容。 使用封装,我们可以根据需要将字段设置为只读或只写。用户也不知道数据如何存储在字段中。 我们可以在setter方法中使用一些特殊加密并将其存储在字段中。 例如,人类是一个对象。 我们只要求用户读取人的名称字段,而不是要修改。 然后我们在name字段上只定义get方法。这就是封装是如何有用的。
封装背后的主要思想是数据隐藏。 我们在面向对象编程中使用封装有几个原因。 我们封装原因的一些确定原因如下( 封装的真实用途 )。
-
更好的可维护性 :当所有属性都是私有和封装时,我们很容易通过更改方法来维护程序。
-
简化调试 :这符合上述要点。 我们知道该对象只能通过方法进行操作。 因此,这使得调试和捕获错误变得容易。
-
拥有受控环境 :让用户以受控方式通过对象使用给定对象。
-
隐藏复杂性 :隐藏与用户无关的复杂性。 有时,某些属性和方法仅供内部使用,用户无需了解这些属性和方法。 这使得用户很容易使用该对象。
因此,回答这个问题,“ 当我能够使用setter方法更改属性值时,封装的用途是什么? ”,上面给出了我们使用封装的一些主要原因。 为了理解为什么,吸气剂和制定者有用 ,下面给出了从本文获得的一些重要观点。
-
您可以限制可以存储在字段中的值(即性别必须为F或M)。
-
您可以在修改字段时执行操作(触发事件,validation等)。
-
您可以通过同步方法来提供线程安全性。
-
您可以切换到新的数据表示(即计算字段,不同数据类型)
如果你有类,它的所有属性都是私有的 – 这意味着它们不能从类外部访问 – 并且与类属性交互的唯一方法是通过它的公共方法。
您通过向公众提供对这些方法(setter)的访问来更改tha值。
使用封装,类的字段可以是read-only
或read-only
write-only.
而不是让所有人直接访问变量:
public Object object;
最好使用SET和GET方法,或者仅使用GET方法(有时你不希望没有人为该变量设置其他值)。
public Object getObject() { return object; } public void setObject(Object object) { this.object = object; }
通过使用封装,您可以将类与外部世界(其他类)分开,并且外部世界可以通过访问修饰符访问和修改类实例变量,这提供了以下几个好处:
– 你可以在你的getter / setter方法中做一些记录。
– 您可以validation/标准化(例如修剪空格,删除特殊字符,…)您在setter方法中的输入。
而且你也可以从外部世界隐藏你的实现,例如你的类中有一个类似数组列表的集合,你就像这样编写你的getter方法
public List get collection(){ return new ArrayList (this.arrayList); }
所以在这种情况下,将来如果您决定将集合列表中的集合实现更改为链表等其他内容,您可以自由地这样做,因为外面的世界对您的实现一无所知。