那些年一起学过的面向对象之:4 面向对象的三大特征:封装、继承、多态

面向对象的三大特征

  • 封装(Encapsulation)

封装,可以望文生义,即将东西封装起来,不让别人知道,当然,自己可以知道,指定信得过的人也可以知道。

封装将数据和行为封装起来,并对对象的使用者隐藏了数据的实现方式。

其实,一个对象就是封装了数据和操作这些数据的代码的逻辑实体。

在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。这就为对象内部数据提供了保护的作用,防止被意外修改。

好处:

1提高重用性(封装)

2提高可靠性(隐藏)

3方便对象的使用者使用(隐藏了复杂性)

  • 继承

现实世界中,很多东西都不是相互孤立的,它们往往具有相同的特征,也存在差异。

 

上图反应了人类的派生关系。最高层往往具有最普遍的特征,越往下层越具体,并且下层包含上层的特征。

在程序设计中,这种关系叫做继承。一个类从另外一个类派生出来,派生类继承了父类的所有特性,并且可以添加自己的特性。通过继承所创建的新类叫做子类(或派生类),被继承的类叫做父类(或基类、超类),继承的过程是从一般到具体的过程。

继承是is-a的关系,是一种用于表示特殊与一般的关系。

在考虑使用继承时,如果两个类的关系是“is-a”的关系,即说“XXX是XXX”成立的话,继承关系就成立了。如:说“男人是人”,说得通吧;要是说“王八是人”,看人家不!@&#%#¥。

在面向对象中,继承是非常优秀的语言机制,有如下优点:

1提高代码的重用性;

2代码共享,减少创建类的工作量,因为,每个子类都拥有父类的属性和方法;

3提高代码的可扩展性;

4子类可以形似父类,又可以异于父类。

当然,也有缺点:

1继承是入侵的。只要继承,就必须拥有父类的所有属性和方法;

2降低了代码的灵活性。子类必须拥有父类的所有属性和方法,让子类的自由世界多了约束。试想,要是“老爹”是个品行不正,是个酒鬼,“儿子”被坑大了。

3增强了耦合性。当父类被修改时,必须考虑子类的修改,可能导致大片的代码需要重构。

  • 多态(polymorphisn)

所谓多态,就是父类型的引用可以指向子类型的对象(或接口类型的引用可以指向实现该接口的类的实例)

如: 

 
//动物
public class Animal {
     //动物都会
     public void cry() {
         System.out.println( "(动物叫)" );
     }
}
  
  
//狗,继承于动物
public class Dog extends Animal {
     //狗有它自己的叫法
     @Override
     public void cry() {
         System.out.println( "汪汪" );
     }
}
  
public class Test {
     public static void main(String[] args) {
         //Dog dog = new Dog();
         //dog.cry();        
         Animal animal = new Dog(); //父类型的引用可以指向子类型的对象
         animal.cry(); //输出:汪汪
     }
}

实现多态,有二种方式:覆盖、重载。

覆盖:是指子类重新定义父类的方法。

重载:是指方法名相同,参数列表不同。

可以这么理解:

覆盖,不但不用祖宗那套功夫,而且还自己创一套新的代替祖宗那套;

重载,你是你,我还是我。

覆盖,为纵向关系;重载,为横向关系。

接下来应该注意了。

1其实,重载的概念并不属于“面向对象编程”,重载的实现是编译器根据函数不同的参数列表,对同名函数的名称进行修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如有2个同名函数function func(p:integer):integer和function func(p:string):integer,那么编译器做过修饰后的函数名称可能是int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的(记住是静态)。也就是说,它们的地址在编译期就绑定了(早绑定)。因此,重载和多态无关!

 

2真正和多态相关的是“覆盖”。当子类重新定义了父类的函数后,父类指针根据赋给它的不同的子类指针,动态(记住是动态)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚邦定)。

 

3结论:

a重载只是一种语言特性,与多态无关,与面向对象也无关。引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚邦定,它就不是多态。”

b多态是晚绑定;

c多态是一种运行期行为,不是编译器的行为;

d不要把重载理解为多态,重载是编译时就确定的;

e构成多态的条件:继承、重写、父类引用子类的对象。

 

4那么,多态的作用是什么呢?

我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类)。它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用。多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

原文地址:https://www.cnblogs.com/snake-hand/p/3144965.html