面向对象之多态
----云智科技学习笔记
多态
定义:某一类事物的多种存在形态。
- 例:动物中猫,狗。
- 猫这个对象对应的类型是猫类型
• 猫 x = new 猫();
- 同时猫也是动物中的一种,也可以把猫称为动物。
• 动物 y = new 猫();
• 动物是猫和狗具体事物中抽取出来的父类型。
• 父类型引用指向了子类对象。
1. 程序中体现:
父类或者接口的引用指向或者接收自己的子类对象。
2. 好处和作用:
多态的存在提高了程序的扩展性和后期可维护性
3. 前提:
• 需要存在继承或者实现关系
• 要有覆盖操作
4. 弊端:只能使用父类的引用去访问父类中的成员。
5. 多态:指不同对象收到相同消息时,会产生不同行为。同一个类在不同场合下表现出不同的行为特征。
6. 看如下代码:
abstractclass Animal
{
public abstract void eat();
}
class Catextends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Dogextends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void kanMen()
{
System.out.println("看门");
}
}
class Pigextends Animal
{
public void eat()
{
System.out.println("吃饲料");
}
public void gongDi()
{
System.out.println("拱地");
}
}
publicclass Demo
{
public static void main(String agrs[])
{
/*
Cat c1=new Cat();
c1.eat();
Cat c2=new Cat();
c2.eat();
Cat c3=new Cat();
*/
//发现向上面这样调用太麻烦
//写了下面的方法来调用
function(new Cat());
function(new Dog());
function(new Pig());
//通过方法的重载实现了如下功能
//但是发现,动物类会有很多子类,如果每个子类都写个对应的方法,太麻烦了
//引入多态的概念,对代码进行优化
}
public static void function(Cat c)
{
c.eat();
}
//因为狗也有类似需求
public static void function(Dog d)
{
d.eat();
}
//因为猪也有类似需求
public static void function(Pig p)
{
p.eat();
}
}
7. 优化后的代码:
abstractclass Animal
{
public abstract void eat();
}
class Catextends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Dogextends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void kanMen()
{
System.out.println("看门");
}
}
class Pigextends Animal
{
public void eat()
{
System.out.println("吃饲料");
}
public void gongDi()
{
System.out.println("拱地");
}
}
publicclass Demo2
{
public static void main(String agrs[])
{
/*
Cat c1=new Cat();
c1.eat();
Cat c2=new Cat();
c2.eat();
Cat c3=new Cat();
*/
//发现向上面这样调用太麻烦
//写了下面的方法来调用
Animal c=new Cat();
function(c);
Animal d=new Dog();
function(d);
Animal p=new Pig();
function(p);
//引入多态的概念,对代码进行优化
}
public static void function(Animal a)
{
a.eat();
//但是在这个方法中,只能是调用父类的方法,如果想调用子类的方法,请看Demo3.java
}
}
8. 再次优化后的代码:
abstractclass Animal
{
public abstract void eat();
}
class Catextends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Dogextends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void kanMen()
{
System.out.println("看门");
}
}
class Pigextends Animal
{
public void eat()
{
System.out.println("吃饲料");
}
public void gongDi()
{
System.out.println("拱地");
}
}
publicclass Demo3
{
public static void main(String agrs[])
{
/*
Cat c1=new Cat();
c1.eat();
Cat c2=new Cat();
c2.eat();
Cat c3=new Cat();
*/
//发现向上面这样调用太麻烦
//写了下面的方法来调用
Animal c=new Cat();
function(c);
Animal d=new Dog();
function(d);
Animal p=new Pig();
function(p);
//引入多态的概念,对代码进行优化
}
public static void function(Animal a)
{
a.eat();
//但是在这个方法中,只能是调用父类的方法,如果想调用子类的方法,可以这么做
if(a instanceof Cat)
{
Cat c=(Cat)a;
c.catchMouse();
}else if(a instanceof Dog)
{
Dog d=(Dog)a;
d.kanMen();
}else if(a instanceof Pig)
{
Pig p=(Pig)a;
p.gongDi();
}
}
}
类型转换:向上转型、向下转型
Animal a=new Cat( );//类型提升,将父类的引用指向了子类
Cat c=(Cat) a ;//强制类型转换,将原来的父类的引用从新转换成该子类对象的引用
但是下面的操作是不允许的:
Animal a=new Animal( );
Cat c=(Cat) a;//这种转换是不允许的。
所以,我们看到,我们能转换的是父类的引用指向了自己的子类对象时,该引用可以被提升,也可以被转换。多态自始至终都是子类对象在做着变化。
多态的特点
- 成员函数:
• 口诀:编译看左边,运行看右边。
• 编译时:要查看引用变量所属的类中是否有所调用的成员。
• 在运行时:要查看对象所属的类中是否有所调用的成员。
• 总结:其实在加载进内存时,是加载的是子类的字节码文件,但是只是用来父类型的引用指向,若用父类型的引用去调用时,只能访问父类型中的成员,但是还存在着把该字节码文件强制类型转换成子类的可能,强转后,便有了新的子类引用指向该字节码文件,就可以调用子类和父类中的所有的成员了。
- 成员变量:
• 只看引用变量所属的类。即只参考左边,引用类型的类型。
- 静态成员:
• 无论在编译还是运行,都参考引用类型。
多态的应用
//学生学习案例
abstract class Student
{
publicabstract void study();
publicvoid sleep()
{
System.out.println("躺着睡觉");
}
}
class DoStudent
{
publicvoid doSome(Student s)
{
s.study();
s.sleep();
}
}
class BaseStu extends Student
{
publicvoid study()
{
System.out.println("basestudy");
}
publicvoid sleep()
{
System.out.println("坐着睡觉");
}
}
class AdvStu extends Student
{
publicvoid study()
{
System.out.println("AdvStustudy");
}
}
public class Demo
{
publicstatic void main(String args[])
{
DoStudentds=new DoStudent();
ds.doSome(newBaseStu());
ds.doSome(newAdvStu());
}
}
//电脑主板案例
class MainBoard
{
publicvoid run()
{
System.out.println("mainbord run");
}
publicvoid usePCI(PCI p)
{
if(p!=null)
{
p.open();
p.close();
}
}
}
interface PCI
{
publicvoid open();
publicvoid close();
}
class NetCard implements PCI
{
publicvoid open()
{
System.out.println("netcartopen");
}
publicvoid close()
{
System.out.println("netcartclose");
}
}
class SoundCard implements PCI
{
publicvoid open()
{
System.out.println("SoundCardopen");
}
publicvoid close()
{
System.out.println("SoundCardclose");
}
}
public class Demo
{
publicstatic void main(String args[])
{
MainBoardm=new MainBoard();
m.run();
m.usePCI(null);
m.usePCI(newNetCard());
m.usePCI(newSoundCard());
}
}