我尝试了解很多次,但我没理解这一点。
封装是将类中的字段设为私有的技术 并通过公共方法提供对田地的访问。如果是一个领域 声明私有,它不能被课外的任何人访问, 从而隐藏了班级中的字段。
我们如何通过setter方法更改字段的值?我们如何防止直接访问字段?封装的真正用途是什么?
答案 0 :(得分:26)
假设您有age
属性。
用户可以输入值-10
,虽然这是有效数字,但是年龄无效。 setter方法可以有逻辑,允许你捕获这些东西。
另一种情况是拥有age
字段,但隐藏它。你也可以有一个出生日期字段,在它的设置器中你会有这样的东西:
...
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.
}
答案 1 :(得分:14)
在我阅读“面向对象编程语言中的封装和继承”一书以及解释封装重要性的网站之前,我也一直很困惑。实际上,我是从网站上直接导读的。
人们总是说封装是"隐藏信息"因此,也许,将封装集中在安全性上作为主要用途。是的,你在实践中隐藏信息,但这不应该是定义,因为它可能会让人感到困惑。
封装只是通过定义严格的外部接口来最小化单独编写的模块之间的相互依赖关系。 (引自书中)。也就是说,当我构建一个模块时,我想要我的客户和我之间就如何访问我的模块签订严格的合同。原因是,这样我就可以改善内部运作而不影响我的客户,生活,应用程序或他们使用我的模块的任何东西。因为他们的"模块"并不完全取决于我的模块的内部工作方式,而是依赖于"外部接口",我可以使用它。
所以,如果我没有为我的客户提供一个setter并让他们直接访问变量,我意识到我需要在我的客户端使用它之前对变量设置一些限制,我改变它,可能是我,改变我的客户的生活,或用巨额费用申请我的客户。但如果我提供了严格的合同"通过创建一个严格的外部接口"即setter,那么我可以很容易地改变我的内部工作,而不是花费我的客户。
在setter情况下(使用封装),如果它发生在您设置变量时,我返回一条消息通知您已分配,现在我可以通过我的"接口&#34发送消息;告知我的客户我的模块必须与之交互的新方式,即"你不能分配负数"即如果我的客户尝试分配负数。但是,如果我没有使用封装,并让我的客户端直接访问变量,我做了我的更改,它可能导致崩溃的系统,因为,如果我实施的限制,是,你,你无法保存负面和我的客户端我总是能够存储负面信息,我的客户手中会有一个崩溃的系统(如果那个"崩溃的系统"是一个银行系统,想象会发生什么)。
因此,封装更多的是减少模块之间的依赖性,因此可以进行改进"安静地"与其相互作用的其他模块的费用很少或没有,而不是安全性。因为交互模块依赖于"严格的外部接口或严格的合同"。
我希望这能正确解释。如果没有,你可以去下面的链接并自己阅读。
Encapsulation and Inheritance in Object-Oriented Programming Languages
答案 2 :(得分:10)
封装的真正用途还在于您可以对设置值的方式进行额外的检查/处理。
答案 3 :(得分:5)
您并没有完全阻止对字段的访问 - 您正在控制其他人访问某些字段的方式。例如,您可以向setter方法添加验证,或者也可以在调用字段的setter方法时更新其他一些依赖字段。
您可以阻止对该字段的写入或读取访问(例如,仅分别提供一个getter或setter) - 但是使用属性进行封装可以让您做更多的事情。
答案 4 :(得分:3)
我可以通过setter方法更改字段值。
只有使用setter方法才能执行此操作。
我们如何阻止访问字段?
setter和getter可以控制是否以及如何访问这些字段。
设定者可以检查该值是否有效。它可能会询问SecurityManager是否允许您这样做。它可以在数据类型之间转换。等等。
答案 5 :(得分:3)
如果你有私有字段,他们不能在课外访问,这意味着基本上这些字段不存在于外部世界,是的你可以通过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
S.o.p("access denied");
}
想象一下,如果薪水是公开的并且可以直接访问任何可以随时更改它,无论何时他们想要,这基本上是封装的重要性
答案 6 :(得分:2)
封装背后的主要思想是数据隐藏。我们在面向对象编程中使用封装有几个原因。我们封装原因的一些原因如下(实际使用封装)。
更好的可维护性:当所有属性都是私有和封装的时候,我们很容易通过更改方法来维护程序。
轻松调试:这符合上述要点。我们知道该对象只能通过方法进行操作。因此,这使得调试和捕获错误变得容易。
拥有受控环境:让用户以受控方式通过对象使用给定对象。
隐藏复杂性:隐藏与用户无关的复杂性。有时,某些属性和方法仅供内部使用,用户不必了解这些属性和方法。这使得用户可以很容易地使用该对象。
所以,回答这个问题," 当我能用setter方法更改属性值时,封装的用途是什么?",如上所述是我们使用封装的一些主要原因。为了理解为什么,getter和setter是有用的,下面给出了一些重要的观点,从这个article获得。
您可以限制可以存储在字段中的值(即性别必须为F或M)。
您可以在修改字段时执行操作(触发事件,验证等)。
您可以通过同步方法来提供线程安全性。
您可以切换到新的数据表示(即计算字段,不同数据类型)
答案 7 :(得分:1)
它的目标只是保护任何易于改变的东西。你在网上有很多例子,所以我给你一些优点:
immutable class
答案 8 :(得分:1)
通过方法访问字段会产生差异,因为它会使其成为OOP。例如,您可以扩展您的课程并更改您无法直接访问的行为。如果你有getter / setter,你可以代理你的类,做一些AOP或做一个1.4动态代理。你可以从你的班级做一个模拟并进行单元测试......
答案 9 :(得分:1)
让我们假设您使用以下setter / getters创建自定义Date类:
getDay()
getMonth()
getYear()
setDay()
setMonth()
setYear()
在内部,您可以使用以下方式存储日期:
private int day;
private int month;
private int year;
或者您可以使用java.lang.Date-object存储日期:
private Date date;
封装不会暴露您的类在内部的工作方式。它让您可以更自由地改变课程的运作方式。它为您提供了控制对类的访问的选项。您可以检查用户输入的内容是否有效(您不希望用户输入值为32的日期)。
答案 10 :(得分:1)
Encapsultaion用于隐藏成员变量,方法是将成员设为私有,并通过getter和setter方法访问该成员变量。
示例
类封装{
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());
}
}
您无法访问课堂外的私人价值。
答案 11 :(得分:1)
嗯,封装并不是关于隐藏数据的全部内容。这一切都是为了控制存储在字段中的内容。使用封装,我们可以根据需要将字段设置为只读或只写。用户也不知道数据如何存储在字段中。我们可以在setter方法中使用一些特殊加密并将其存储在字段中。 例如,人是一个对象。我们只要求用户读取人的名称字段,而不是要修改。然后我们在名称字段上仅定义get方法。这就是封装的有用方式。
答案 12 :(得分:0)
如果你有类,它的所有属性都是私有的 - 这意味着它们不能从类外部访问 - 并且与类属性交互的唯一方法是通过它的公共方法。
您正在通过向公众提供对这些方法(设置者)的访问来更改值。
使用封装可以将类的字段设为read-only
或write-only.
答案 13 :(得分:0)
而不是让所有人直接访问变量:
public Object object;
最好使用SET和GET方法,或者仅使用GET方法(有时你不希望没有人为该变量设置其他值)。
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
答案 14 :(得分:0)
通过使用封装,您可以将您的类与外部世界(其他类)分开,并且外部世界可以通过访问修饰符访问和修改您的类实例变量,这提供了以下几个好处:
- 你可以在你的getter / setter方法中做一些记录。
- 您可以验证/标准化(例如修剪空格,删除特殊字符,...)您在setter方法中的输入。
而且你也可以隐藏你的实现与外部世界,例如你的类中有一个像数组列表的集合,你就像这样编写你的getter方法
public List<t> get collection(){
return new ArrayList<t>(this.arrayList);
}
所以在这种情况下,将来如果您决定将集合列表中的集合实现更改为链表等其他内容,您可以自由地这样做,因为外面的世界对您的实现一无所知