Java中的抽象?

时间:2011-09-02 14:04:53

标签: java

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

public class employee {

     private String name;
     private int id;

     public void setName(String name){
         this.name = name;
     }

     public String getName(){
         return name;
     }
}

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

11 个答案:

答案 0 :(得分:9)

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

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

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;
     }
}

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

public Customer implements Person {
     private String name;
     private integer moneySpent;

     public String getName() {
          return name;
     }
}

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

在抽象级别处理对象时,方法的名称在抽象中共享;但是,执行的实际代码取决于对象的未提及的基础类型。换句话说,如果您询问某人(恰好是员工)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<Animal> animals = new ArrayList<Animal>();
       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!

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

答案 1 :(得分:4)

@ 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中以加密形式保存它,那么是什么。 用户不关心加密但是你必须......因为它对用户不利但对你很重要。所以这应该在你的代码中,但对用户隐藏,这就是抽象的全部*(“隐藏来自用户的不合理的详细信息”)*

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

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

interface NameService {
    String getName();
}

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

答案 6 :(得分:1)

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

答案 7 :(得分:1)

  

但这里的抽象在哪里?

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

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

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

答案 8 :(得分:1)

java official documentation for you to understand when to use interface or abstraction.

另外,我不禁注意到您在封装和抽象之间感到困惑,所以这里是 geekforgeeks 网站上它们之间的简单区别

<块引用>

封装是数据隐藏(信息隐藏)而,

<块引用>

抽象是详细隐藏

(实现隐藏)。

封装将数据和作用于数据的方法组合在一起,数据抽象处理将接口暴露给用户并隐藏实现细节。

答案 9 :(得分:0)

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

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

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

Learn how to use an Abstract Class in Object Oriented Design

The Theory of Abstraction

答案 10 :(得分:0)

要隐藏数据时要进行抽象;要隐藏数据和代码时要进行封装,即要包装要实现的数据和代码。

您可以使用抽象类或接口来实现抽象。 在抽象类中,我们可以编写具体方法或抽象方法,但在接口中,我们只能使用抽象方法。

您可以使用访问修饰符(例如public,protected,private)来实现封装。 这些访问修饰符控制数据的访问,即数据是公开的(任何人都可以看到)还是受保护的(只能由扩展类访问)还是私有的(对所有人隐藏)。