Java 中的抽象?
今天听朋友说,封装不仅是实现信息隐藏,而且是抽象。它是如何实现的呢?
public class employee {
private String name;
private int id;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
上面的示例实现了封装,我允许类访问我的公共方法而不是私有成员,但是抽象在哪里出现呢?谁能以一种清晰的方式向我解释一下抽象。
Today i heard from my friend, that encapsulation is not only achieving information hiding but also abstraction. How does it achieve?
public class employee {
private String name;
private int id;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
The above example achieves encapsulation where i am allowing the class to access my public method rather than private members, but where does the abstraction come into picture here? Can anyone explain me on abstraction in a bit clear manner.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
有两种不同的东西,信息隐藏和抽象。
信息隐藏使抽象成为可能,但它是不同的。例如,使用您的代码
id
字段实际上是隐藏的。这允许人们以一种与程序的其余部分解耦的方式处理 id。您的名称字段实际上也是隐藏的,因为您不直接访问名称字段,但getName
和setName
中的代码可以访问。一旦您对其余代码隐藏了数据结构,强制通过方法进行访问,就可以创建一个项目的许多可替换实现。例如,
employee
是一种person
的概念,因此您可以像这样重写上面的内容:现在您的代码可以处理
Employee
作为一个人
。重写未显式处理Employee
的其余代码以处理Person
后,您可以实现其他类型的Person
并利用非员工特定任务(现在是人员
任务)。因此,人员搜索例程,只要它仅索引
Person
对象,现在就可以包括对Employee
和Customer
的搜索。这是因为处理Person
对象的代码实际上是在处理Employee
和Customer
对象共享的更高级别的抽象。当在抽象级别上处理对象时,方法的名称在整个抽象中共享;但是,实际执行的代码取决于未提及的对象的基础类型。换句话说,如果您询问一个 Person(恰好是一名员工)
getName()
,那么它将使用Employee.getName()
函数进行响应,而code>Customer
将使用Customer.getName()
函数进行响应。由于调用getName()
的代码是在Person
上操作的,因此它不知道它将处理哪种类型的人,但行为上的明显变化(选择基于每个对象的正确代码块)仍然会发生。这种现象被称为多态性,如果您第一次接触这些概念,您会听到多态性这个词被频繁使用。多态行为的一个例子:
预期输出:
即使我们从未显式更改类,也从未显式更改方法。抽象方法与显式子类的绑定正在发生变化,这种情况只发生在支持多态性的系统中。
There's two different things, information hiding and abstraction.
Information hiding makes abstraction possible, but it is something different. For example, using your code
The
id
field is actually hidden. This allows one to handle ids in a manner that is decoupled from the rest of the program. Your name field is actually hidden too, as you don't access the name field directly, but the code ingetName
andsetName
does.Once you hide the structure of the data from the rest of the code, forcing access through methods, it is possible to create a number of replaceable implementations of an item. For example, an
employee
is a conceptual kind ofperson
, so you could rewrite the above like so:Now your code can deal with the
Employee
as aPerson
. After rewriting the rest of the code that doesn't explicitly deal withEmployee
s to deal withPerson
s, you could implement other kinds ofPerson
s and leverage the non-Employee specific tasks that are nowPerson
tasks.So a person searching routine, as long as it only indexes
Person
objects can now include searches of bothEmployee
s andCustomer
s. This is because the code dealing withPerson
objects is actually dealing with a higher level abstraction that bothEmployee
andCustomer
objects share.When dealing with Objects on an abstract level, the names of the methods are shared across the abstraction; but, the actual code executed depends on the unmentioned underlying type of the object. In other words, if you ask a Person (who happens to be an employee)
getName()
then it will respond with theEmployee.getName()
function, while aCustomer
will respond with aCustomer.getName()
function. Since the code callinggetName()
is operating onPerson
s it has no idea which type of person it will be handling, but the apparent change in behavior (the selection of the right block of code on a per-object basis) still happens. This phenomena is known as Polymorphisim, and if you are first hitting these concepts, you'll hear Polymorphisim as a word used a lot.An example of polymorpic behavior:
expected output:
even though we never explicitly changed classes, and we never explicitly changed methods. It was the binding of the abstract method to the explicit subclass that was changing, which is something that only happens in systems that support polymorphisim.
@约翰,你的朋友是对的,通过实现封装,你也实现了抽象。
通过这种方式,您已经编辑了您的设置方法并向用户隐藏了细节,这只是抽象......
因此,通过编写 getter 和 setter,您可以隐藏用户来执行不必要的任务...
我知道将 id 添加到名称是一个愚蠢的例子,但这就是我现在能想到的...但是考虑到您多次编写的一个非常大的项目set 中的代码(或调用其他修改其参数的方法)然后……
假设您获得了名称,但想将其以加密形式保存在数据库中,那么该怎么办。
用户不关心加密,但是是的,您必须...因为它对用户来说是不必要的,但对您来说很重要。因此,这应该在您的代码中,但对用户隐藏,这就是抽象的全部内容*(“向用户隐藏不必要的细节”)*
编辑:-转到源代码! Grady Booch 说道(《面向对象的分析与设计》,第 49 页,第二版):
“抽象和封装是互补的概念:抽象侧重于对象的可观察行为……封装侧重于引起这种行为的实现。 ..封装通常是通过信息隐藏来实现的,这是隐藏对象的所有秘密的过程,这些秘密对其基本特征没有贡献。”
从上面你可以得出同样的结论
@ John your friend is right by implementing the encapsulation you also achieve abstraction.
in this way you have edited ur set method and hided the details from the user which is nothing but abstraction...
thus by writting getters and setters you hide user to do the unneccessary task...
I know adding id to name is a stupid example but thats what i can think of right now... but consider for a very big project you many times write code in set(or call other method which modifies the parameters of it) then what...
suppose you get the name but you want to save it in a encrypted form in db, then what.
User dont care about the encryption but yes you have to... because its uneccesary to the user but important to you. So that should be in the code of yours but hidden from the user and thats what is all about abstraction*("HIDING THE UNNECCESARY DETAILS FROM USER")*
EDITED:-Go to the source! Grady Booch says (in Object Oriented Analysis and Design, page 49, second edition):
"Abstraction and encapsulation are complementary concepts: abstraction focuses on the observable behavior of an object... encapsulation focuses upon the implementation that gives rise to this behavior... encapsulation is most often achieved through information hiding, which is the process of hiding all of the secrets of object that do not contribute to its essential characteristics."
from above you can conclude the same
我认为他混淆了多态性和封装。多态性可以帮助您实现抽象。
I think he's confusing polymorphism with encapsulation. Polymorphism can help you achieve abstration.
这里主要是封装,但也有一些抽象。通过使用名为
setName()
的方法,使用您的类的代码不需要知道您如何实现“设置名称”的操作。据他们所知,您正在调用网络服务并将其设置在数据库中的某个位置。或者您可能完全忽略该参数并将名称每次都设置为“Steven”。这些事实是从调用者那里抽象出来的。It's mostly encapsulation here, but there is some abstraction as well. By using a method called
setName()
, code that consumes your class doesn't need to know how you're implementing the operation of "setting a name". For all they know, you're calling out to a webservice and setting it in a database somewhere. Or maybe you're ignoring the parameter entirely and setting the name to "Steven" every time. Those facts are abstracted away from the caller.我认为你无法用这个特定的例子来证明封装性。它更像是这样:
现在,告诉我:实现此接口的类是否从平面文件、数据库、nosql 存储或其他地方获取名称?
I don't think you can prove encapsulation with that particular example. It's more like this:
Now, tell me: does a class implementing this interface get the name from a flat file, a database, a nosql store, or someplace else?
抽象是关于无法实现/实例化的概念/模型。
抽象就是对对象的方法/成员行为对其他类的限制。
Abstraction is all about a concept/model which cannot be realized / instantiated as such.
Abstraction is all about restriction on an object's method/members behaviour to other classes.
就我个人而言,我不会说封装真正是关于抽象的(尽管我知道如何以这种方式实现),它只是允许用户查看或执行必要的操作 - 他们只看到一个接口类,而不是其内部运作。在您的情况下,它的实现是因为您只设置或获取特定类的名称,您从不直接访问名称变量,也从不查看它是如何存储的。因此,您可以将名称变量的名称或类型更改为完全不同的名称,并且类的接口仍然可以工作并且看起来相同。我想这在某种意义上可以被视为一种抽象。
定义很松散,但我认为多态性更多地属于抽象领域,在抽象领域中,您将实现(例如,
ArrayList
)与其继承的接口(例如,List< /code>。)这样你只需处理列表接口,底层列表可以是任何东西,但这是一个实现细节,因为你是它“之上”的抽象级别,所以你不需要担心它。当然,这是一种简化,有时出于性能原因您需要了解实现细节,或者某些操作可能无法在您的特定实现上实现或允许。但从宽松的观点(以及纯粹的面向对象的观点)来看,它是成立的。
无论您理解它是什么,最重要的是您了解其背后的逻辑,为什么这是一个好主意以及为什么这样做总是更好(在这种情况下,将字段设置为私有并使用 getters / setters 来访问他们。)
Personally I wouldn't say encapsulation is really about abstraction (though I see how it could be taken that way), it's about only permitting a user to see or do what's necessary - they only see an interface to the class, not its inner workings. In your case it's achieved because you're only ever setting or getting the name of the particular class, you never access the name variable directly and never see how it's stored. So you could change the name or type of the name variable to something completely different and the interface to your class would still work and look the same. I guess that could be taken in a sense as an abstraction.
The definitions are loose, but I'd consider polymorphism to fall more into the realms of abstraction, where you decouple the implementation (say,
ArrayList
) from the interface it inherits (say,List
.) That way you just deal with the list interface, and the underlying list could be anything, but that's an implementation detail and because you're an abstract level "above" it, you don't need to worry about it. Of course this is a simplification, sometimes you need to know implementation details for performance reasons or if some operations may not be implemented or allowed on your specific implementation. But from a loose viewpoint (and a pure OO viewpoint) it holds.Whatever you understand it to be, the most important thing is you understand the logic behind it, why it's a good idea and why it's always better to do things that way (in this case, have fields as private and use getters / setters to access them.)
你自己说过:“允许类访问我的公共方法而不是私有成员”
或者换句话说:允许其他类访问他们可以访问的内容,并保护他们不能访问的内容。
这里的抽象来自公共方法,例如在
getName()
中,您不需要总是给出私有成员值,它可以附加其他值,甚至可以给出完全不同的东西。这就像在说:“告诉我你的名字,无论你如何告诉我”。也许更好的例子是名为getYourWorkDone()
的方法。原则仍然是一样的:“完成你的工作!如何?我不在乎如何!”封装部分来自私有成员。这个类封装了那些私有成员,因此它们被分组以形成类的状态。
you've said it yourself: "allowing the class to access my public method rather than private members"
or in other words: allowing other classes to access what they may access, and protecting what they may not.
the abstraction here comes from the public methods, for instance in
getName()
you don't need to always give the private member value, it could be appended with other value or even it could give totally different thing. it's like saying: "tell me your name, regardless how you'd give it to me". maybe a better example would be a method namedgetYourWorkDone()
. the principle remains the same: "get your work done! how? I don't care how!"the encapsulation part is from the private members. this class encapsulates those private members so they are grouped to form the class' state.
java官方文档,让您了解何时使用接口或抽象。
另外,我不禁注意到您对封装和抽象感到困惑,所以这里是 geekforgeeks 网站上它们之间的简单区别
(实现隐藏)。
封装将数据和作用于数据的方法组合在一起,数据抽象处理向用户公开接口并隐藏实现的细节。
java official documentation for you to understand when to use interface or abstraction.
Also, I couldn't help notice that you were confused between encapsulation and abstraction so here is a simple difference between them for geekforgeeks website
(implementation hiding).
Encapsulation groups together data and methods that act upon the data, data abstraction deal with exposing the interface to the user and hiding the details of implementation.
看来封装和抽象让大家都感到困惑了。如果你问我,这些都是截然不同的话题,绝对没有任何混乱的范围。
当您使用“abstract”关键字时会发生抽象,而当您创建类时会发生封装。封装的良好实现包括将所有数据成员设为私有。
我写了一些博客文章,可能会对您有所帮助:
了解如何在对象中使用抽象类面向设计
抽象理论
It seems encapsulation and abstraction has got everyone confused. If you ask me, those are poles-apart topics and there is absolutely no scope of confusion in this.
abstraction happens when you use "abstract" keyword, and encapsulation happens when you create a class. a good implementation of encapsulation involves making all your data members private.
I wrote a few blog posts that might help you:
Learn how to use an Abstract Class in Object Oriented Design
The Theory of Abstraction
当您想要隐藏数据时,就完成了抽象。而当您想要同时隐藏数据和代码时,就完成了封装。即包装您实现的数据和代码。
您可以使用抽象类或接口来实现抽象。
在抽象类中,我们可以编写具体方法,也可以编写抽象方法,但在接口中,我们只能使用抽象方法。
您可以使用 public、protected、private 等访问修饰符来实现封装。
这些访问修饰符控制数据的访问,即数据是否应该是公共的(任何人都可以看到)或受保护的(只能由扩展类访问)或私有的(对所有人隐藏)。
Abstraction is done when you want to hide the data.Whereas encapsulation is done when you want to hide both data and code.That is wrapping both data and code which you implement.
You can implement abstraction by using abstract class or interface.
In abstract class we can either write concrete methods or abstract methods but in interface we can only use abstract methods.
You can implement encapsulation by using access modifiers like public, protected, private.
These access modifiers control the access of your data i.e whether it should be public(can be seen by anyone) or protected(can be accessed only by extended classes) or private(hiding it from everyone).