【问题标题】:Abstraction in Java?Java中的抽象?
【发布时间】:2011-11-09 05:20:51
【问题描述】:

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

public class employee {

     private String name;
     private int id;

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

     public String getName(){
         return name;
     }
}

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

【问题讨论】:

    标签: java oop abstraction


    【解决方案1】:

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

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

    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 中的代码可以。

    一旦您对其余代码隐藏了数据结构,强制通过方法进行访问,就可以创建一个项目的许多可替换实现。例如,employeeperson 的概念类型,因此您可以像这样重写上面的代码:

    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。在重写未明确处理Employees 的其余代码以处理Persons 后,您可以实现其他类型的Persons 并利用现在为Person 的非员工特定任务任务。

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

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

    在抽象级别处理对象时,方法的名称在抽象之间共享;但是,实际执行的代码取决于对象的未提及的底层类型。换句话说,如果你问一个人(恰好是雇员)getName(),那么它会用Employee.getName() 函数响应,而Customer 会用Customer.getName() 函数响应。由于调用getName() 的代码在Persons 上运行,它不知道它将处理哪种类型的人,但行为的明显变化(基于每个对象选择正确的代码块)仍然发生。这种现象被称为 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!
    

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

    【讨论】:

    • @edwin...在评论时删除了评论我刚刚看到了代码...对此我感到非常抱歉。再次非常抱歉...
    • 请也总结一下你的答案......从上面的描述中你可以得出结论,封装实现了抽象......我在某些方面看到了它。但它是给约翰的。他应该很清楚这个概念。
    • 不,封装不能实现抽象。它使抽象成为可能。要看到一个人,必须忽略差异,只关注共同点,比如身高和年龄。每个人都有身高和年龄(共性),但并不是每个人都有我祖父的金怀表或我的钢笔(差异化)。如果我们不能封装微分器,那么抽象就会变得非常困难,因为没有将微分器与共性区分开来,并且作用于共性的代码可能会通过偷看微分器来真正完成工作而作弊。
    【解决方案2】:

    @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 页,第二版):

    “抽象和封装是互补的概念:抽象关注对象的可观察行为……封装关注引起这种行为的实现……封装通常通过信息隐藏实现,即过程隐藏所有与其本质特征无关的对象秘密。”

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

    【讨论】:

    • @downvoter...我错误地发布了没有写下整个答案,请现在看看...
    【解决方案3】:

    我认为他将多态性与封装混淆了。多态可以帮助你实现抽象。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        interface NameService {
            String getName();
        }
        

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

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

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

            【讨论】:

              【解决方案8】:

              但是这里的抽象体现在哪里?

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

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

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

              【讨论】:

                【解决方案9】:

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

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

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

                抽象是细节隐藏

                (实现隐藏)。

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

                【讨论】:

                  【解决方案10】:

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

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

                  我写了几篇博文可能对你有所帮助:

                  Learn how to use an Abstract Class in Object Oriented Design

                  The Theory of Abstraction

                  【讨论】:

                    【解决方案11】:

                    当你想隐藏数据时进行抽象。而当你想隐藏数据和代码时进行封装。即包装你实现的数据和代码。

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

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

                    【讨论】:

                      猜你喜欢
                      • 2011-07-23
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-09-04
                      • 2011-01-23
                      • 2011-08-26
                      • 1970-01-01
                      • 2015-12-06
                      相关资源
                      最近更新 更多