------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
第一讲 多态
一、多态的含义
面向对象的多态特征,简而言之就是“对外一个接口,内部多种实现”。面向对象程序设计语言支持两种形式的多态:运行时多态和编译时多态。编译时多态主要是通过重载(overloading)技术实现的,即在一个类中相同的方法名可用来定义多种不同的方法。运行时的多态是在面向对象的继承性的基础上建立的,是运行时动态产生的多态性,是面向对象的重要特性之一。二、方法重载(overloading)
有时,我们需要在同一个类中定义几个功能类似但参数不同的方法。这种定义方式比较麻烦。Java语言提供了方法重载机制。就是定义一个函数名称以表示起功能,方便阅读,而通过参数列表的不同来区分多个同名函数。重载方法的名称都是相同的,但在方法的声明中一定要有彼此不同的成分,以使编译器能够区分这些方法:
1、方法的参数表必须不同,包括参数的类型或个数,以此区分不同方法体。
2、方法的返回值类型、修饰符可以相同也可以不同。
练习:判断show()方法是否重载?
void show(int a,char b,double c){}
a.
void show(int x,char y,double z){}//没有,因为和原函数一样。
b.
int show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。
c.
void show(int a,double c,char b){}//重载,因为参数类型不同。注意:重载和返回值类型没关系。
d.
boolean show(int c,char b){}//重载了,因为参数个数不同。
e.
void show(double c){}//重载了,因为参数个数不同。
f.
double show(int x,char y,double z){}//没有,这个函数不可以和给定函数同时存在与一个类中。
三、方法重写(overriding)
1、子类中父类成员的隐藏和方法重写子类中的成员变量与父类中的成员变量同名时,子类的成员变量会隐藏父类的成员变量。子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写。父类中的私有方法不可以被覆盖。在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取。
2、覆盖注意事项:
(1)覆盖时,子类方法权限一定要大于等于父类方法权限
(2)静态只能覆盖静态。
3、覆盖的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
4、重载和重写的区别:
重载:只看同名函数的参数列表。
重写:子父类方法要一模一样。
四、运行时多态
类之间的继承关系使子类具有父类的所有变量和方法,这意味着父类所具有的方法也可以在它所派生的够级子类中使用,发给父类的任何信息也可以发给子类。所以子类的对象也是父类的对象,即子类对象即可以作为该子类的类型,也可以作为其父类的类型对待。因此从一个基础父类派生的各种子类都可以作为同一种类型——基础父类的类型对待。将一种类型(子类)对象的引用转换成另一种类型(父类)对象的引用,就称为上溯造型。
1、多态的体现
父类的引用指向了自己子类的对象。
父类的引用也可以接收自己的子类对象。
2、多态的前提
类与类之间必须有关系,要么继承,要么实现。
存在覆盖。父类中有方法被子类重写。
(1)在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
(2)在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
(3)在多态中,静态成员函数的特点:
无论编译和运行,都参考做左边。
4、多态的利弊:
多态的好处
(1)多态的出现大大的提高程序的扩展性。
对于一个类体系可以动态增加新的类型或减少类型,已经存在的访问这个类体系对象的代码依然可以正常工作。
(2)使程序易于编写,易于维护,并且易于理解。
因为在对具有继承关系的一组类进行处理时,只要根据这个类中的基础类接口编写一个方法就可以了,不用针对不同的子类专门编写代码。因此将简化程序的编写并易于维护,也使程序结构得到简化,易于理解。
多态的弊端:
虽然提高了扩展性,但是只能使用父类的引用访问父类中存在的成员。如果想要调用子类特有方法时,强制将父类的引用。转成子类类型。向下转型。
5、对象类型的强制转换
对象的强制类型转换也称为向下造型,是将父类类型的对象变量强制(显示)地转换为子类类型。Java中允许上溯造型的存在,使得父类类型的变量可以指向子类对象,但通过该变量只能访问父类中定义的变量和方法,子类特有的部分被隐藏,不能进行访问。只有将父类类型变量强制转换为具体的子类类型,才能通过该变量访问子类的特有成员。
格式:
Father father=new Son();
Son son=(Son) father;
在Java中使用instanceof测试对象的类型。格式:a instanceof A;当a是A类型时,表达式返回值为true,否则false。
6、多态示例:
需求:电脑运行实例,
电脑运行基于主板。
<span style="font-family:SimSun;font-size:14px;">
interface PCI //定义接口PCI,通过接口实现主板运行时的多态。
{
public void open();
public void close();
}
class MainBoard //定义主板
{
public void run()
{
System.out.println("mainboard run ");
}
public void usePCI(PCI p)//接口型引用指向自己的子类对象。如:PCI p = new NetCard()
{
if(p!=null)
{
p.open(); //调用PCI子类对象的函数。
p.close();
}
}
}
class NetCard implements PCI //网卡实现PCI,通过上溯造型可以用PCI的对象调用网卡的函数。
{
public void open() //实现接口定义的方法。
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
}
}
class SoundCard implements PCI //声卡实现PCI,通过上溯造型可以用PCI的对象调用声卡的函数。
{
public void open() //实现接口定义的方法。
{
System.out.println("SoundCard open");
}
public void close()
{
System.out.println("SoundCard close");
}
}
class DuotaiMainBoard
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard(); //创建主板对象。
mb.run(); //对象调用函数。
mb.usePCI(null); //参数为空,什么也不做。
mb.usePCI(new NetCard()); //将网卡的对象作为PCI的对象使用,
//通过PCI调用网卡的函数。
mb.usePCI(new SoundCard()); //将声卡的对象作为PCI的对象使用,
// 通过PCI调用声卡的函数。
}
}</span>
运行结果: