`

基本概念继承,封装,多态,重载

阅读更多

封装就是把各种方法和变量合并到一个类,用这个类代表某个对象为完成一定的任务所能保存的范围以及它能执行的操作。

继承就是根据现有类的方法和成员变量生成新的类的功能

多态就是对象随着程序执行而使其形式发生改变的能力。

抽象就是在暂时忽略对象的具体细节的功能。

1,为什么要继承

继承的好处是代码重用.哲学上讲事物都是有共性和特性的.把共性函数代码放入到父类中,把特性函数代码放入到子类中,当然是否共性要以参照点的标准.OO中所谓的抽象我自己理解为哲学中的共性

在同一个行业中,他们各业务流程往往有很大的相似性,但往往我们都是到一个项目中就重新写一套流程代码,或者粘贴以前的代码.可能有很多代码都是以前写过的重复代码.造成重复劳动.如果采用继承应该这样,首先在父类中做一个基本上大部分行业项目都必要的简洁的主流程.在子类中针对具体项目的特殊性做主流程充分的完善的补充.这样在每个项目中,只针对项目的特殊性编写代码,大大降低重复劳动.当然根据具体流程的复杂多可以划分多的继承层次,呈现一种继承的树结构,但一定的要保证层次一定要有实际的意义.

举个事实来验对:
一个群体,比如说一个班级,可以是一个类了,
再细分一下,有老师,这也是一个类
有学生,又是一个类
那他们有没有共性,当然是有的,那就是才是人
所以人就是基类。
先做好人的基类,然后继承这个基类来造学生类,
也继承人这基类来造老师类,
这样,可以组装(就是封装)成班级类了
在继承类的过程中,由于不同对象相同的属性或方法去表现出来的效果不尽一致,
因此就要重载这些方法或属性了
相同的动作,由于针对不同对象效果也不一样,那就呈现出多态性了,
比如,学生做作业和老师做作业那肯定是不同的性质,如果你还是不懂的话可以问问老师,
看看他做作业和你做作业是不是性质不同的两回事。

比较抽象,只是一种概念,刚开始学的时候无需太过于深究,如果要你一上来学JAVA就理解这些东西,有点牵强,你所要做的就是至少看到代码知道这个用到的是什么。

封装的概念好比一辆汽车,你学开车的时候只需学会诸如踩油门、刹车,转方向盘即可,无需去了解它的发动机是如何发动。

继承,先说说我对类的理解,类起到的作用有:分类(你所用某个类创建的对象实际上该类的个案)和模板的作用,那么继承则起到了对类再次分类的作用,比如,有个类“动物”,“哺乳动物”继承“动物”,再往下“马”又继承了“哺乳动物”这个类。在这里,我们从下往上讲,首先,我们把某种东西划分出来,叫做“马”(当然还有“牛”,“鱼”等等),接着,我们发现,“马”,“羊”等还有很多共同的特点,于是,我们再次划分出了“哺乳动物”这个类,再次分类,我们则有了“动物”。但在实际开发中,我们一般是从上往下定义的,即先有了“动物”,再有“哺乳动物”,最后有“马”。

多态,正如上面朋友所说一重写,二重载。用汉字来打个比方,比如“开”这个字,在不同的时候各有的意思,比如“开门”,“开窗”,甚至有“开车”,“开饭”等,具有相同名称但操作不同。具体的实现我就不累述了。

说说接口吧,在JAVA不支持多继承的,实际上接口起到了类似多继承的作用,一个类只能继承另一个类(或抽象类)但可以实现多个接口。打个比方,“张三”,他是一个“人”,因此他继承了“人”;与此同时,他是一个“司机”,他的平时行为还有“开车”,很显然,这并不能从“人”这个类里继承下来。怎么办?JAVA里只支持单继承,这个时候,接口就起到了作用,它定义了“司机”这个接口,“张三”实现了它,因此,他会开车了。

2,为什么要封装

高内聚低偶合的思想简单的理解同一模块内的提高内聚,不同模块降低偶合.如果说一个类代表一个模块或是一个业务流,那么A类内部要提高内聚,类的属性可以看成是内的局部变量.提高数据的重用.公共函数尽量能被其他主函数,尽量达到功能内聚.如果说是A类和B,并且是不同模块(也许是同一个模块下的两个子模块),那么B是不能使用A的函数和属性的,紧进行数据偶合.封装的作用就体现在这里.

再现实中就项目中经常遇到这种情况,某项业务增加或修改一种类型的业务流,自己本身调试成功了,但是缺影响了此业务下其他的业务流,不得不测试所有得其他原本正常的业务流并不得不针对此做类型判断的补丁,这种补丁很肯能导致程序结构的不合理.

3.为什么多态

个人认为多态的好处体现在代码的可扩充性,比如一个业务有多个业务流,为了区别不同的类型就的使用判断,那么新添加一个流程就得在过程执行主流程(往往是final,必然是面向过程的)中添加一个”if then”或是重载一个函数

在目前项目中mvc得控制器就是典型的多态.想想如果我们不使用多态那么怎么办?因为对PO对象是新添加的,那么必须针对新的PO对象在代码中做IF判断,才能用他本身的对象类型指向他.造成过程执行主流程不断的要变更自己的代码.

总结:

OO中继承和多态互相依赖又互相矛盾,没有继承就不可能有多态,多态的使用往往又在面向过程的代码中.继承是使子类可以使用父类的功能,而多态使父类能使用子类的功能.

OO并非只是在编码阶段来处理,实际上在概要设计,详细设计,数据库设计的时候就应该OO的思想来设计.提高软件可重用性和可扩充性.对于想对一个行业做标准化产品软件而言,很重要.

来点接近生活的:(转贴)
面向对象就是面向你老婆,你跟她说“去倒茶”,她就会把茶到好;你说“老婆.衣服.颜色=红”,她就自己去把红色衣服换上。当你老婆做饭时,她会产生一个“帮忙”事件,当然,你可以选择处理或者不处理这个事件:P。你可以让老婆生Baby,这就是继承;老婆不会告诉你她有多少钱,这就是封装;老婆高兴了一个样,不高兴一个样,这就是“多态”……

你老婆面向对象就是你老婆面向你

她跟你说“去倒茶”,你就会把茶到好;她说“老公.香烟.Enable=false”,你就会乖乖把香烟戒掉。当你给老婆做饭时,你会产生一个“帮忙”事件,当然,她可以选择处理或者不处理这个事件:P。你老婆要是不想生Baby,那你就没得被继承;你存私房钱,这就是封装;你外面泡妞对这个一个样,对那个一个样,这就是“多态”,老婆让你打扫家里卫生,你把所有房间垃圾都清理一遍,这叫循环遍历,找到的垃圾装到垃圾带里,这叫装箱,把垃圾丢进了楼下垃圾箱里,这叫垃圾清理,忽然发现你不小心把自己包私房钱的报纸也丢了进去,赶紧去垃圾堆翻出来,这叫拆箱,找了半天没找到,发现垃圾已经被清扫工给收走了,啥呆呆的站在垃圾箱旁边,这叫挂起 ……

老婆说"咱们买别墅吧",可你口袋太瘪,这就是虚拟函数;十年后你攒够了钱,买下别墅,就是重载;发现你买的别墅是十年前盖的,马上要拆了,就是销毁.

谈恋爱叫类设计;结婚叫实例化;双方的私房钱都是private属性的;教育储蓄是protectd属性的,只能留给继承者用,别人不能用;只有抽屉里的零钱是 public 属性的,谁都可以用;离婚叫 GC;离了婚又藕断丝连叫弱引用;再婚叫重载

老婆说我渴了去给我买瓶可乐,我在这里等着,这叫同步调用
老婆说家里没米了你快去买米烧饭我先去买衣服了,这叫异步调用

封装性、继承性和多态性

类的基本特性包括封装性、继承性和多态性。
一、封装
通过将类成员变量的访问作用域声明为private可以实现类的封装性。
二、重载
方法重载:
类的方法名不应该和同类的其他方法名一致,如果这样将使编译器很难识别应该调用哪一个类
的方法。比如,有一种加法运算,该运算能够完成对两个整数相加,但是在实际应用的时候,我们发现对两个浮点数求和也是很常用的,这是我们需要另外一个求和的方法用于对两个浮点数求和。按照“类的方法其方法名不应该和同类的其他方法一致”的原则,对两个整数求和以及对两个浮点数求和的方法的名不应该一致。我们可以对两个整数求和的方法取名为“addInt”,而对两个浮点数求和的方法取名为“addFloat”。这样固然能够解决问题,但是这种解决办法却给变成人员带来很多不便,变成人员对于同一种操作(都是加法运算)却需要记住不同的函数名。庆幸的是C#为我们提供了函数重载和操作符重载的机制,通过方法重载或者操作符重载,♂能够实现统一种操作使用同样的函数名,而不影响程序的正常运行。
类中如果有两个以上的方法取得名字相同,只要是用的参数类型或者参数个数不同,编译器就知道在何种情况下应该调用哪个方法,这就是方法的重载。譬如构造函数,我们定义不带参数的构造函数,同时也定义了带参数的构造函数,而且这辆种类型的构造函数是可一同是在类中存在的,也就是说一个类中可以有多个构造函数。这些构造函数虽然名字相同,但是这些构造函数中使用的参数类型或者参数个数是不同的。在一个类中定义多个构造函数其时就是重载的一个应用。在类中,不仅构造函数能够重载,类的方法也能够重载。在类中如果有两个以上的方法取得名字相同,只要使用的参数类型或者参数个数不同这就是方法重载。
注意,两个方法只有参数不同或者参数个数不同才称为方法重载,如果是两个方法只是返回值类型不同,那么这两个方法不是重载,并且在编译的时候将引发错误。
操作符重载:
在面向对象的设计中,自己定义一个类就是创建一种新的数据类型。类的对象和变量一样可以作为函数参数,也可以作为函数的返回值的类型。
<!--等待补充 -->
三、类的继承性
继承性广泛存在于现实世界的对象之中。在一个系统中,如果所有的类都处于同一个层次上,这种没有相互关系的平面结构就会限制系统的面相对象的特性,而且使得软件的抽象不能真正反映现实世界对象的特性。特性的引入,就是在类之间建立一种相互关系,是的新定义的派生类的实例可以继承积累得特性和能力,而且可以加入新的特性或者修改已有的特性,建立类的层次结构。
因为新定义的派生类可以继承基类的特性和能力,所以继承性提高了软件模块的可复用性,提高了软件的开发效率。又可以新定义的派生类可以加入新的特性或者修改已有的特性,所以继承性同样提高了软件的可扩充性。我们总是希望能够利用前人或者以前自己的开发成果,同时又希望自己的开发过程中能够有足够的灵活性而不拘泥于服用的模块。C#提供的继承性能够满足软件开发的可复用性和可扩充性的要求。
1.1.封装(encapsulation)
1.事物的内部实现细节隐藏起来
2.对外提供一致的公共的接口――间接访问隐藏数据
3.可维护性

1.2.继承(inherit)
1.2.1.JAVA继承特点
继承:父类的成员能否继承到子类?
子类能否访问到父类的成员

private:本类内部可以访问不能继承到子类
(default):本类内部可以访问,同包其他类也可以访问
能否继承到子类?不一定

protected:本类内部可以访问,不同包的子类也可以访问,同包其他类也可以访问
能继承到子类
public:任何地方都可以访问能继承到子类

从严到宽

(override)覆盖的构成条件:
1、方法名:相同
2、参数表:相同(个数,类型)
3、访问限制符:相同或者更宽
4、返回值类型:相同或者子类返回的类型是父类返回的类型的子类
5、不能抛出比subclass(父类)更多的异常

对象的构造过程:
1.递归的构造父类对象
2.分配空间
3.初始化属性
4.调用本类的某一个构造方法,并用在方法的第一句。

super:调用父类的某一个构造方法
父类对象
不能出现在static方法内

多态:
1.对象不变
2.只能对对象调用编译时类型中定义的方法
3.运行时,根据对象的运行时类型,找覆盖过的方法来调用(运行时动态类型判定)

强制类型转换instanceof

屏蔽子类差异,利用父类共性做出通用编程

属性的遮盖(shadow)没有多态
方法的重载看参数的编译时类型

1.2.2.父类(SuperClass)和子类(SubClass)的关系
父类的非私有化属性(不同包的子类无法访问default修饰符)和方法可以默认继承到子类。
ClassSonextendsFather{
}
而如果父类中的私有方法被子类调用的话,则编译报错。
父类的构造方法子类不可以继承,更不存在覆盖的问题。
所以子类构造方法默认调用父类的无参构造方法。(所以养成写无参构造的习惯)
如果子类访问父类的有参构造方法,必须在子类构造方法第一行使用super(参数)
当构造一个对象的时候,系统先构造父类对象,再构造子类对象。
PublicclassBMWcarextendsCar{
PublicBMWcar(){
Super(intalength);//显式的调用父类的构造,默认调用无参构造
//所以父类没有无参构造的话,子类如果不加显示调用其他构造就会报错。这里的super是一个对父类的引用
}
}

1.2.3.系统构造一个对象的顺序
1先为最里层类成员属性赋初值;
2再构造该类对象;
3返回外层,重复1(上一层类)、2步骤直到完成最外层类的构造。

最外层类

最里层基类

<!--[if!vml]-->最外层类[里层类]


注意:super()this()不会同时出现
A(){
super();
}
A(inta){
this();
}
1.3.多态(polymorphism)
多态:一个对象变量可以指向多种实际类型的现象。

1.3.1.方法的覆盖(overridding)

当子类从父类继承一个无参方法,而又定义了一个同样的无参方法,则子类新写的方法覆盖父类的方法,称为覆盖。(注意返回值类型也必须相同,否则编译出错。)
如果方法参数表不同,则成重载。
特点:
1.对于方法的访问限制修饰词,子类方法要比父类的访问权限更高。
父类为public,那么子类为private则出现错误。
2.子类抛出的异常应该是父类抛出的异常或其子类。

1.3.2.多态的分类
多态分两种:
1编译时多态:编译时动态重载;
2运行时多态:指一个对象可以具有多个类型,方法的覆盖
这样对于对象而言分为:
理解运行时多态:
Carc=newBus();
Car编译时类型编译时检查变量类型是否存在,是否有调用的方法
Bus运行时类型实际运行是访问heep中的对象,调用实际的方法。
运行时多态是由运行时类型决定的
编译时多态是由编译时类型决定的
猫,小鸟,狗都是动物,都可以安上动物的标签。
InterfaceAnimal{}
ClassCarimplementsAnimal{}
ClassBirdimplementsAnimal{}
ClassDogimplementsAnimal{}
方法中
Animala=newCar();
Animalb=newBird();
Animalc=newDog();

*方法重载看的是参数的编译时类型

publicclassAnimal{
publicstaticvoidmain(String[]args){

}
}


(1)是覆盖吗?不能多态了
abstractclassMyClass{
priavatevoidm();
}
classSubextendsMyClass(){
publicvoidm();
}
(2)错误的修饰符组合
abstractclassMyClass{
priavateabstractvoidm();
}
classSubextendsMyClass(){
publicvoidm();
}
(3)5.0新非覆盖
abstractclassMyClass{
privatefinalvoidm();
}
classSubextendsMyClass(){
publicvoidm();
}


1.3.3.运行时多态的三原则
1.对象不变;(改变的是主观认识)
2.对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。
在上面的例子中:Animala=newDog();对象a的编译时类型为Animal,运行时类型为dog。
注意:编译时类型一定要为运行时类型的父类或者同类型。
对于语句:Dogd=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就可以调用运行时类型。注意:a和d指向同一对象。
3.动态类型判定实际调用的方法。即它调用覆盖后的方法。

封装(Encapsulation):封装是一个面向对象的概念,对外部世界,隐藏类的内部.

封装优点:

1.好的封装能减少耦合.

2.类的内部的实现可以自由改变.

3.一个类有更清楚的接口.

Data Hiding(数据隐藏):封装的一个最有用的形式是数据隐藏.一个类的数据表现一个对象的状态.

修饰符支持封装:

Private:只有类本身能存取.

Protected:类和派生类可以存取.

Internal:只有同一个项目中的类可以存取.

Protected Internal:是Protected和Internal的结合.

Public:完全存取.

other Encapsulating Strategy:(其他封装策略)属性和索引器的目的是封装一个类的细节和给类的用户提供一个公共的接口.

封装和继承的关系:

封装的意思是包容(聚合),类与类之间的关系是"has a".一个类里面有另一个类.

继承,类与类之间的关系是"is a".


多态(Polymorphism):就是怎样重载一个虚拟类.多态是面向对象的重要概念.

Implementing Polymorphism(实现多态):

例子:

using System;

public class WebSite

{

public string SiteName;

public string URL;

public string Description;


public WebSite()

{

}


public WebSite( string strSiteName, string strURL, string strDescription )

{

SiteName= strSiteName;

URL= strURL;

Description = strDescription;

}


public override string ToString()

{

return SiteName + ", " +

URL+ ", " +

Description;

}

}


abstract public class Contact

{

public virtual string UpdateNotify()

{

return "Web Site Change Notification";

}

}


public class Customer : Contact

{

public new string UpdateNotify()

{

return @"

This is to let you know your

favorite site, Financial Times,

has been updated with new links";

}

}


public class SiteOwner : Contact

{

WebSite mySite;


public SiteOwner(string aName, WebSite aSite)

{

mySite = new WebSite(aSite.SiteName,

aSite.URL,

aSite.Description);

}


public new string UpdateNotify()

{

return @"

This is to let you know your site, " + "\n" +

mySite.SiteName + @", has been added as

a link to Financial Times.";

}

}


public class Test

{

public static void Main()

{

WebSite leFin = new WebSite("Le Financier",

"http://www.LeFinancier.com",

"Fancy Financial Site");


Contact[] Contacts = new Contact[2];


Contacts[0] = new SiteOwner("Pierre Doe", leFin);

Contacts[1] = new Customer();


foreach (Contact poc in Contacts)

{

if (poc is SiteOwner)

{

Console.WriteLine("Message: {0}\n",

((SiteOwner)poc).UpdateNotify());

}

else

{

Console.WriteLine("Message: {0}\n",

((Customer)poc).UpdateNotify());

}

}

}

}

在例子中,Contact类有个虚拟方法,有两个派生类分别实现.使用了"new"关键字.

可以有更有效和优雅的方法,实现它,就是多态.

例子:

using System;

abstract public class Contact

{

public virtual string UpdateNotify()

{

return "Web Site Change Notification";

}

}


public class Customer : Contact

{

public override string UpdateNotify()

{

return @"

This is to let you know your

favorite site, Financial Times,

has been updated with new links";

}

}


public class SiteOwner : Contact

{

string siteName;


public SiteOwner(string sName)

{

siteName = sName;

}


public override string UpdateNotify()

{

return @"

This is to let you know your site, " + "\n" +

siteName + @", has been added as

a link to Financial Times.";

}

}

public class Test

{

public static void Main()

{

Contact[] Contacts = new Contact[2];


Contacts[0] = new SiteOwner("Le Financier");

Contacts[1] = new Customer();


foreach (Contact poc in Contacts)

{

Console.WriteLine("Message: {0}\n",

poc.UpdateNotify());

}

}

}


例子中,派生类用"override"实现了多态.

虚拟方法是允许多态工作的基类的方法.用"override"修饰符说明,能被派生类重载.虚拟方法和抽象方法的不同


时,虚拟方法有实现,抽象方法没有.抽象方法,隐式说明是虚拟,必须被重载;虚拟方法不必被重载.


多态,必须是虚拟方法,而且,方法的签名必须一致,包括方法名称,参数,和参数类型.

例子:

abstract public class Contact

{

public virtual string UpdateNotify()

{

return "Web Site Change Notification";

}

}


public class Customer : Contact

{

public override string SendMail() {}// error


public override string UpdateNotify(int number) {}// error

}

例子中,SendMail不是虚拟方法,故错误;UpdateNotify,带有不同的参数,故也错误.


new 和 override 修饰符,都可以实现新的方法.但,new 实现的是派生类新的方法.

例子:

using System;


abstract public class Contact

{

public virtual string UpdateNotify()

{

return "Web Site Change Notification";

}

}


public class Customer : Contact

{

public new string UpdateNotify()

{

return @"

This is to let you know your

favorite site, Financial Times,

has been updated with new links";

}

}


public class SiteOwner : Contact

{

string siteName;


public SiteOwner(string sName)

{

siteName = sName;

}


public override string UpdateNotify()

{

return @"

This is to let you know your site, " + "\n" +

siteName + @", has been added as

a link to Financial Times.";

}

}


public class Test

{

public static void Main()

{

Contact[] Contacts = new Contact[2];


Contacts[0] = new SiteOwner("Le Financier");

Contacts[1] = new Customer();


foreach (Contact poc in Contacts)

{

Console.WriteLine("Message: {0}\n",

poc.UpdateNotify());

}

}

}

结果是:

Message:

This is to let you know your site,

Le Financier, has been added as

a link to Financial Times.


Message: Web Site Change Notification

例子中,Customer 用"new"实现新的方法,但是,在运行是不是多态.仍然调用基类的方法.


Most-Derived Implementations(多重派生实现)


Polymorphic Properties(多态的属性):C#允许,属性的多态实现.

例子:

using System;


public class SiteStats

{

public int numberOfVisits = 0;

}


abstract public class Contact

{

protected string name;


public virtual string Name

{

get

{

return name;

}

set

{

name = value;

}

}

}


public class Customer : Contact

{

SiteStats myStats = new SiteStats();


public override string Name

{

get

{

myStats.numberOfVisits++;

Console.WriteLine("Number of visits: {0}",

myStats.numberOfVisits);


return name;

}

set

{

base.Name = value;

myStats.numberOfVisits = 0;

Console.WriteLine("Name: {0}", Name);

}

}

}


public class Test

{

public static void Main()

{

Contact myContact = new Customer();

myContact.Name = "George";

}

}

例子中,抽象类,有属性Name,派生类重载实现了属性.


Polymorphic Indexers(多态的索引器):索引器的多态.

例子:

using System;

using System.Collections;

public class SiteList

{

protected SortedList sites;


public SiteList()

{

sites = new SortedList();

}


public int NextIndex

{

get {

return sites.Count;

}

}


public virtual string this[int index]

{

get

{

return (string) sites.GetByIndex(index);

}

set

{

sites[index] = value;

}

}

}


public class FinancialSiteList : SiteList

{

public override string this[int index]

{

get

{

Console.WriteLine("FinancialSiteList Indexer Get");

if (index > sites.Count)

return (string)null;


return base[index];

}

set

{

Console.WriteLine("FinancialSiteList Indexer Set");

base[index] = value;

}

}

}


class SiteManager

{

SiteList sites = new SiteList();


public static void Main()

{

SiteManager mgr = new SiteManager();


mgr.sites = new FinancialSiteList();


mgr.sites[mgr.sites.NextIndex] = "Great Site!";


Console.WriteLine("Site: {0}",

mgr.sites[0].ToString());

}

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics