------- android培训、java培训、期待与您交流! ----------
众所周知,面向对象思想有三大特征:封装,继承,多态。
下面详细说说多态。
举个例子,猫对应的类型是猫类型,同时也是动物类型,很明显动物是猫的父类。我们在创建猫对象的时候,可以用:
猫 cat = new 猫();也可以用:动物cat = new 猫();第二种方法就是父类型引用指向了子类对象。这种现象就是多态。
由此可见,多态就是同一事物在不同时刻体现出来的不同状态。
多态的体现:父类或者接口的引用指向或者接收自己的子类对象。
多态的前提:
1、 必须类与类之间有关系,要么是继承关系,要么是实现关系
2、 要有方法的覆盖
举例:class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("functionFu");
}
}
//继承关系
class Ziextends Fu {
public int num = 1000;
public int num2 = 200;
//覆盖操作
public void show() {
System.out.println("showZi");
}
public void method() {
System.out.println("methodzi");
}
public static void function() {
System.out.println("functionZi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//父类引用指向子类对象。
Fuf = new Zi();
}
}
多态中成员访问的特点:
1、 成员变量:
编译看左边,运行也看左边。
2、 成员函数:
编译看左边,运行看右边。
3、 构造函数:
创建子类的对象的时候,访问父类的构造方法,对父类的数据进行初始化。
4、 静态函数:
编译看左边,运行也看左边。(静态是和类相关的)
举例:
class Fu {
public int num = 100;
public void show() {
System.out.println("showFu");
}
public static void function() {
System.out.println("functionFu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("showZi");
}
publicvoid method() {
System.out.println("methodzi");
}
public static void function() {
System.out.println("functionZi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//父类引用指向子类对象。
Fu f = new Zi();
System.out.println(f.num);//结果为1000
//System.out.println(f.num2);//编译时就找不到符号
f.show();//编译看父类有show方法,编译通过,运行时看子类有show方法,输出show Zi
//f.method();//编译时看父类没有method方法,编译不通过
f.function();//编译看父类有method方法,编译通过,运行时看子类有method方法,输出function Zi
}
}
多态的好处:
1、 提高了代码的可维护性(由继承保证);
2、 提高了代码的可扩展性(由多态保证)
举例:
现在有父类:Animal 和两个子类:Cat和Dog;对这两个子类的对象进行维护
//父类
abstract class Animal
{
abstract void eat();
}
//创建子类并覆盖父类方法
class Cat extends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
//创建子类并覆盖父类方法
class Dog extends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void watchHome()
{
System.out.println("看家");
}
}
class DuoTaiDemo
{
publics tatic void main(String[] args)
{
Catc = new Cat();//创建一个Cat对象
c.eat();//调用Cat类中的方法
Dogd = new Dog();//创建一个Dog对象
d.eat();//调用Dog类中的方法
}
}
在此基础上,如果又增加了Pig对象,那我们可以直接创建Pig类继承Animal类,并在主函数中创建Pig对象和调用Pig类中的方 法。可见多态的出现使程序的维护和扩展变得容易。
但是发现多态有个弊端:虽然提高了扩展性,但是使用父类的引用只能访问父类中的成员,不能使用子类的特有功能。
如果要使用子类的特有功能呢?当然可以如上面的例子中这样创建子类对象然后调用方法,但是很多时候会不合理,占内存, 也是代码的重复性很高。对此java提供了另外一种方式:向下转型,即将父类的引用强制转换为子类的引用,
格式:子类名子类对象名 = (子类名)父类对象名;
那么,我们如果要在上例中加入Pig对象,可以将创建对象和调用方法功能封装起来,并用父类引用强转为子类引用,改进的 代码如下:
abstract class Animal
{
abstrac tvoid eat();
}
class Cat extends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void watchHome()
{
System.out.println("看家");
}
}
class Pig extends Animal
{
public void eat()
{
System.out.println("吃饲料");
}
public void gongDi()
{
System.out.println("拱地");
}
}
class DuoTaiDemo
{
public static void main(String[] args){
function(newCat());
function(newDog());
function(newPig());
}
//定义一个方法将建立对象和调用方法封装
public static void function(Animal a)//形参是用父类引用接收子类对象
{
a.eat();
if(a instanceof Cat)
{
//判断a的类型,然后强转
Catc = (Cat)a;
c.catchMouse();
}
elseif (a instanceof Dog)
{
Dogd = (Dog)a;
d.watchHome();
}
elseif (a instanceof Pig)
{
Pigp = (Pig)a;
p.gongDi();
}
}
}
千万不能有这样的操作:Animal a = new Animal(); Catc = (Cat)a; 这样是将父类的对象转换成子类类型。我们所能转换 的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强转。多态自始至终都是子类对象再做着变化。