对封装、继承、多态、抽象的理解

封装

封装是面向对象的重要原则,就是把对象的属性和行为(方法)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。大白话讲就是,把不想告诉或者不该告诉别人的东西隐藏起来(private关键字修饰),把可以告诉别人的东西公开,别人只能用我提供的功能实现需求,而不知道内部是如何实现的。正是由于这种特性,所以起到了增加安全性的作用。

继承

继承是面向对象最显著的一个特性,是从已有的类中派生出新的类,我们把它称之为子类,子类继承父类的属性和行为,并能根据自己的需求扩展出新的属性和行为,提高了代码的可复用性。 
eg : 运动Sport,球类运动BallSport继承Sport,羽毛球Badminton继承BallSport。

抽象

抽象表示 将一类实体的共同特性抽象出来,封装在一个抽象类中,所以抽象在面向对象语言是由抽象类来体现的。比如鸟就是一个抽象实体,因为抽象实体并不是一个真正的对象,它的属性还不能完全描述一个对象,所以在语言中体现为抽象类不能实例化。在Java中抽象用 abstract 关键字来修饰,用 abstract 修饰类时,此类就不能被实例化,从这里可以看出,抽象类(接口)就是为了继承而存在的。

eg : 还是多态中的例子,球类运动作为父类定义一个抽象方法play(),然后让继承它的子类具体实现该方法

多态

多态指允许不同的对象对同一个消息做出相应,即同一个消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。封装和继承几乎都是为多态而准备的,在执行期间判断引用对象的实际类型从而调用其相应的方法。 通过传递给父类对象引用不同的子类对象从而表现出不同的行为,多态可为程序提供更好的可扩展性,同样也可以代码重用。

程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性
eg : 球类运动都会有play()打球这个行为(方法),但是这个方法是抽象的(没有具体的实现),子类中的羽毛球实现是用羽毛球拍去打的,而足球是用脚去踢的,篮球是用手去投的。

多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1). 方法重写(子类继承父类并重写父类中已有的或抽象的方法);

          2). 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

  方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种 表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方 法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。方法的重写Overriding和重载Overloading是Java多态性的不同表现。

多态中的两种类型转换:

① 向上类型转换(upcast)(上转型):将子类型转换成父类型。对于向上类型转换,不需要显示指定:

Parent p = newChild();

② 向下类型转换(downcast)(下转型):将父类型转换为子类型。对于向下类型转换,必须要显示指定,使用强制类型转换:

Parent p = newChild();

Child child =(Child)p;

我们可以把JAVA中的类分为以下三种:

基本类: 使用class定义且不含有抽象方法的类。也就是一般的类(一般所说的类就是基本类),是对象的模板,是属性和方法的集合。可以继承其他基本类、抽象类、实现接口。

抽象类:使用abstract class定义的类,它可以含有,也可以不含有抽象方法。有抽象方法的类(抽象方法就是该方法必须由继承来实现,本身只定义,不实现)。抽象类可以有一个或多个抽象方法,他是基本类和接口类的过度。

接口类:使用interface定义的类。一般叫做接口,该类中的所有方法都是抽象方法,该类的方法本身只定义不实现。

抽象类和接口一个由【abstract class + 抽象类名】一个由【interface +接口名】定义,接口中的所以方法都是抽象方法,而抽象类有部分方法是自身实现了的,一些只定义不实现。

在这三种类型之间存在下面的继承规律:

类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。

抽象类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。

接口只能继承(extends)接口。

一个普通类继承一个接口后,必须实现这个接口中定义的所有方法,否则就只能被定义为抽象类。

以上三条规律同时遵守下面这些约束:

类和抽象类都只能最多继承一个类,或者最多继承一个抽象类,并且这两种情况是互斥的,也就是说它们要么继承一个类,要么继承一个抽象类。

类、抽象类和接口在继承接口时,不受数量的约束,理论上可以继承无限多个接口。当然,对于类来说,它必须实现它所继承的所有接口中定义的全部方法。

抽象类继承抽象类,或者实现接口时,可以部分、全部或者完全不实现父类抽象类的抽象(abstract)方法,或者父类接口中定义的接口。

类继承抽象类,或者实现接口时,必须全部实现父类抽象类的全部抽象(abstract)方法,或者父类接口中定义的全部接口。

继承给我们的编程带来的好处就是对原有类的复用(重用)

一、继承、接口与多态的相关问题:

1、 继承的作用?好处?坏处?

继承:通过继承实现代码复用。Java中所有的类都是通过直接或间接地继程java.lang.Object类得到的。继承而得到的类称为子类,被继承的类称为父类。子类不能继承父类中访问权限为private的成员变量和方法。子类可以重写父类的方法,及命名与父类同名的成员变量。但Java不支持多重继承,即一个类从多个超类派生的能力。

优点:a.因为大部分是继承而来的,实现代码重用,减少代码书写量;

           b.很容易修改和扩展已有的实现

缺点:a.打破了封装,因为基类向子类暴露了实现细节

   b.白盒重用,因为基类的内部细节通常对子类是可见的

      c.当父类的实现改变时可能要相应的对子类做出改变

           d.不能在运行时改变由父类继承来的实现

2、 接口的好处?坏处?

优点:帮助Java语言实现一个类似于多继承的功能.但是实现的多继承功能不会使代码中的类之间出现网状关系,而是比较清楚的树状关系,类似于家谱的感觉。

缺点:  如果向一个java接口加入一个新的方法时,所有实现这个接口的类都得编写具体的实现。

3、 多态的作用?好处?坏处?

作用:简单的说就是一个接口,多种实现;继承的表现就是多态(没有继承就没有多态。)

   a.应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。

        b.派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。

优点:a.可替换性(可以替换一存在的代码);

   b.可扩充性(增加新的子类不影响原有类的特性);

     c.接口性;

     d.灵活性;

     e.简化性

缺点:a“遮盖”私有方法。只有非private的方法才能够被笼罩,尽管编译器不会报错,然而也不会遵照我们所渴望的来实行。在导出类中,对于基类中的private方法,优秀采纳不同的名字。

  b域在转型时候的问题。对于成员变量(域),导出类将占有从基类承袭而来的成员变量和自己的成员变量(变量名字相一同也是如此),况且,将分摊不同的存储空间,这么,导出类将具有两个名目一样的域。为了取得基类的域,务须实际地注明super.field能力走访,而默许的域则是导出类自己的域。

  c静态计策是与类相关系的,而非与某个对象相干联的,那么它就不拥有多态行动。

4、 什么是重载?什么是重写?

重载

  a方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。重载Overloading是一个类中多态性的一种表现。

  b Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。

  c重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。

重写

  a父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。

  b若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。

  c子类函数的访问修饰权限不能少于父类的;

5、 什么是组合?

组合:   a通过创建一个由其他对象组合的对象来获得新功能的重用方法

    b新功能的获得是通过调用组合对象的功能实现的

    c有时又叫聚合

优点:a被包含对象通过包含他们的类来访问

      b黑盒重用,因为被包含对象的内部细节是不可见的

      c很好的封装

           d每个类专注于一个任务

          e通过获得和被包含对象的类型相同的对象引用,可以在运行时动态定义组合的方式

缺点:a结果系统可能会包含更多的对象

      b为了使组合时可以使用不同的对象,必须小心的定义接口

二、面向对象设计的六大原则:

1)Open-Close Principle(OCP),开-闭原则,讲的是设计要对扩展有好的支持,而对修改要严格限制。这是最重要也是最为抽象的原则,基本上我们所说的Reusable Software既是基于此原则而开发的。其他的原则也是对它的实现提供了路径。

2)Liskov Substituition Principle(LSP),里氏代换原则,很严格的原则,规则是“子类必须能够替换基类,否则不应当设计为其子类。”也就是说,子类只能去扩展基类,而不是隐藏或覆盖基类;

3)Dependence Inversion Principle(DIP),依赖倒换原则,“设计要依赖于抽象而不是具体化”。换句话说就是设计的时候我们要用抽象来思考,而不是一上来就开始划分我需 要哪些哪些类,因为这些是具体。这样做有什么好处呢?人的思维本身实际上就是很抽象的,我们分析问题的时候不是一下子就考虑到细节,而是很抽象的将整个问题都构思 出来,所以面向抽象设计是符合人的思维的。另外这个原则会很好的支持OCP,面向抽象的设计使我们能够不必太多依赖于实现,这样扩展就成为了可能,这个原则也是另 一篇文章《Design byContract》的基石。

4)Interface Segregation Principle(ISP),接口隔离原则,“将大的接口打散成多个小接口”,这样做的好处很明显。

5)Composition/Aggregation Reuse Principle(CARP),合成/聚合复用原则,设计者首先应当考虑复合/聚合,而不是继承(因为它很直观,第一印象就是“哦,这个就是OO 啊”)。这个就是所谓的“Favor Composition over Inheritance”,在实践中复合/聚合会带来比继承更大的利益,所以要优先考虑。

6)Law of Demeter or Least Knowlegde Principle(LoD or LKP),迪米特法则或最少知识原则,这个原则首次在Demeter系统中得到 正式运用,所以定义为迪米特法则。它讲 的是“一个对象应当尽可能少的去了解其他对象”。也就是又一个关于如何松耦合(Loosely-Coupled)的法则。

 

参考:https://blog.csdn.net/qq598535550/article/details/52984142

        https://blog.csdn.net/zzucsliang/article/details/35567493

posted @ 2018-08-30 15:43  邓不利多  阅读(1265)  评论(0编辑  收藏  举报