Java中的抽象?

今天我从朋友那里听到,封装不仅实现了信息隐藏,还实现了抽象。 它是如何实现的?

public class employee { private String name; private int id; public void setName(String name){ this.name = name; } public String getName(){ return name; } } 

上面的例子实现了封装,我允许类访问我的公共方法而不是私有成员,但这里的抽象在哪里? 任何人都可以用一种清晰的方式向我解释抽象。

有两个不同的东西,信息隐藏和抽象。

信息隐藏使抽象成为可能,但它有所不同。 例如,使用您的代码

 public class employee { private String name; private int id; public void setName(String name) { this.name = name; } public String getName(){ return name; } } 

id字段实际上是隐藏的。 这允许人们以与程序的其余部分分离的方式处理id。 您的名称字段实际上也是隐藏的,因为您不直接访问名称字段,但getNamesetName中的代码确实存在。

一旦从其余代码隐藏数据结构,强制通过方法进行访问,就可以创建一些项目的可替换实现。 例如, employee是一个概念性的person ,所以你可以像这样重写上面的内容:

 public interface Person { public abstract String getName(); } public class Employee implements Person { private String name; private int id; public void setName(String name){ this.name = name; } public String getName(){ return name; } } 

现在,您的代码可以作为Person处理Employee 。 在重写了未明确处理Employee以处理Person的其余代码之后,您可以实现其他类型的Person并利用现在为Person任务的非Employee特定任务。

 public Customer implements Person { private String name; private integer moneySpent; public String getName() { return name; } } 

所以一个人搜索例程,只要它只对Person对象进行索引,现在可以包括对EmployeeCustomer的搜索。 这是因为处理Person对象的代码实际上是处理EmployeeCustomer对象共享的更高级抽象。

在抽象级别处理对象时,方法的名称在抽象中共享; 但是,执行的实际代码取决于对象的未提及的基础类型。 换句话说,如果您询问一个Person(恰好是员工) getName()那么它将使用Employee.getName()函数进行响应,而Customer将使用Customer.getName()函数进行响应。 由于调用getName()的代码在Person上运行,因此它不知道它将处理哪种类型的人,但行为的明显变化(基于每个对象选择正确的代码块)仍然会发生。 这种现象被称为Polymorphisim,如果你是第一次触及这些概念,你会听到Polymorphisim作为一个经常使用的词。

多态行为的一个例子:

  public interface Animal { public abstract String makeSound(); } public class Cow implements Animal { public String makeSound() { return "Moo Moo!"; } } public class Dog implements Animal { public String makeSound() { return "Ruff Ruff!"; } } public class Sheep implements Animal { public String makeSound() { return "Baa Baa!"; } } // this class demonstrates the polymorphic behavior public class Farm { public static void main(String[] args) { ArrayList animals = new ArrayList(); animals.add(new Cow()); animals.add(new Sheep()); animals.add(new Dog()); for (Animal animal : animals) { // this is where the polymorphisim occurs // each animal will make a different sound // because the makeSound method is getting // bound to different blocks of code based // on the exact type of animal class hiding // under the Animal abstraction. System.out.println(animal.makeSound()); } } } 

预期产量:

  Moo Moo! Baa Baa! Ruff Ruff! 

即使我们从未明确地更改类,我们也从未明确地更改过方法。 它是抽象方法与正在改变的显式子类的绑定,这种情况只发生在支持多态性的系统中。

@ John你的朋友是正确的,通过实现封装,你也实现了抽象。

 public class employee { private String name; private int id; public void setName(String name){ name= name+"something that you want to edit"; this.name = name; } public String getName(){ return name; } } 

通过这种方式你已经编辑了你的set方法并隐藏了用户的细节,这只是抽象…因此通过编写getter和setter你隐藏用户来完成不必要的任务……

 public void setName(String name){ /*some internal logic suppose in database you want name *should be added with its id but what user to do with it.*/ this.name = name; } public String getName(){ /* now suppose you have recieved the name from *data base it has id but you want user to know only name then you will write the logic here to show the name.*/ return name; } 

我知道将id添加到name是一个愚蠢的例子,但这就是我现在能想到的……但是考虑一个非常大的项目你多次在set中编写代码(或者调用其他方法来修改它的参数)然后是什么…假设你得到了这个名字,但你想在db中以加密forms保存它,然后是什么。 用户不关心加密,但是你必须……因为它对用户不利但对你很重要。 所以这应该在你的代码中,但对用户隐藏,这就是抽象的全部*(“隐藏用户不相关的详细信息”)*

编辑: – 去源头! Grady Booch说(面向对象分析与设计,第49页,第二版):

“抽象和封装是互补的概念:抽象关注于对象的可观察行为……封装集中在产生这种行为的实现上……封装通常是通过信息隐藏来实现的,这是隐藏所有内容的过程。对象的秘密,对其基本特征没有贡献。“

从上面你可以得出相同的结论

我认为他的多态性与封装相混淆。 多态性可以帮助您实现abstration。

它主要是封装,但也有一些抽象。 通过使用名为setName()的方法,使用您的类的代码不需要知道如何实现“设置名称”的操作。 他们知道,你正在呼叫一个Web服务并将其设置在某个数据库中。 或者你可能完全忽略了参数并且每次都将名称设置为“Steven”。 这些事实是从呼叫者那里抽象出来的。

我不认为你能用这个特定的例子来certificate封装。 它更像是这样的:

 interface NameService { String getName(); } 

现在,告诉我:实现此接口的类是否从平面文件,数据库,nosql存储或其他地方获取名称?

抽象是关于无法实现/实例化的概念/模型。 抽象就是将对象的方法/成员行为限制到其他类。

我个人不会说封装实际上是关于抽象的(尽管我看到它是如何采用的),它只是允许用户看到或做必要的东西 – 他们只看到类的接口,而不是它的内部工作。 在你的情况下,它是实现的,因为你只是设置或获取特定类的名称,你永远不会直接访问名称变量,永远不会看到它是如何存储的。 因此,您可以将名称变量的名称或类型更改为完全不同的类型,并且类的接口仍然可以工作并且看起来相同。 我想这可以从某种意义上看作是一种抽象。

定义是松散的,但我认为多态性更多地落入抽象领域,在那里你将实现(比如, ArrayList )与它inheritance的接口(比如List 。这就是你只需要处理列表接口,底层列表可以是任何东西,但这是一个实现细节,因为你是一个“高于”它的抽象级别,你不需要担心它。 当然这是一种简化,有时您需要了解性能原因的实现细节,或者某些操作可能无法实现或允许您的特定实现。 但是从一个松散的观点(和一个纯粹的OO观点)来看,它是成立的。

无论你理解什么,最重要的是你理解它背后的逻辑,为什么它是一个好主意以及为什么总是以这种方式做事更好(在这种情况下,将字段作为私有字段并使用getter / setter来访问他们。)

但这里的抽象在哪里?

你自己说过:“允许class级访问我的公共方法而不是私人成员”或换句话说:允许其他class级访问他们可能访问的内容,并保护他们可能不会访问的内容。

这里的抽象来自公共方法,例如在getName()你不需要总是给私有成员值,它可以附加其他值,甚至可以给出完全不同的东西。 它就像是在说:“告诉我你的名字,不管你怎么把它给我”。 也许更好的例子是名为getYourWorkDone()的方法。 原则保持不变:“完成你的工作!怎么样?我不在乎怎么做!”

封装部分来自私人成员。 这个类封装了那些私有成员,因此它们被分组以形成类的状态。

似乎封装和抽象让每个人都感到困惑。 如果你问我,这些都是两极分开的话题,绝对没有混淆的范围。

当您使用“abstract”关键字时会发生抽象,并且在创建类时会发生封装。 封装的良好实现涉及将所有数据成员设为私有。

我写了一些可能对你有用的博客文章:

学习如何在面向对象设计中使用抽象类

抽象理论