一、概述
多态:事物的多种体现形态。
比如说:人:男人,女人
动物:猫,狗
猫 x=new 猫();
动物 x=new 猫();
1、多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
2、多态的前提
必须是类与类之间有关系,要么继承,要么实现,
通常还有一个前提:存在覆盖。
3、多态的好处
多态的出现大大地提高程序的扩展性。
扩展性
例
abstract class Animal//父类:动物
{
abstract void eat();//吃什么不好说,抽象化
}
class cat extends Animal//子类:猫 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃鱼");
}
void catchMonse()//特有属性
{
System.out.println("抓老鼠");
}
}
class dog extends Animal//子类:狗 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃骨头");
}
void keepingGuard()//特有属性
{
System.out.println("看家");
}
}
class pig extends Animal//子类:猪 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃饲料");
}
void gongdi()//特有属性
{
System.out.println("拱地");
}
}
class AnimalDemo
{
public static void main(String[] args)
{
function(new cat());
function(new dog());
function(new pig());
}
public static void function(Animal a)
{
a.eat();
}
}
结果输出:
转型
例
abstract class Animal//父类:动物
{
abstract void eat();//吃什么不好说,抽象化
}
class cat extends Animal//子类:猫 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃鱼");
}
void catchMonse()//特有属性
{
System.out.println("抓老鼠");
}
}
class dog extends Animal//子类:狗 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃骨头");
}
void keepingGuard()//特有属性
{
System.out.println("看家");
}
}
class pig extends Animal//子类:猪 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃饲料");
}
void gongdi()//特有属性
{
System.out.println("拱地");
}
}
class AnimalDemo
{
public static void main(String[] args)
{
Animal a=new cat();//类型提升,向上转型,如:byte a=2,int b=a。a的类型提升为int型
a.eat();
//如果想要调用猫的特有方法时,如何操作?
//强制将父类的引用。转成子类类型。向下转型。
cat c=(cat)a;
c.catchMonse();
/*
千万不要出现这样的操作,就是将父类对象转成子类类型。
我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
多态自始至终都是子类对象在做着变化。
Animal a=new Animal();
cat c=(cat)a;
*/
function(new cat());
function(new dog());
function(new pig());
}
public static void function(Animal a)
{
a.eat();
if (a instanceof cat)//类型判断
{
cat c=(cat)a;
c.catchMonse();
}
else if (a instanceof dog)//类型判断
{
dog c=(dog)a;
c.keepingGuard();
}
else if(a instanceof pig)//类型判断
{
pig c=(pig)a;
c.gongdi();
}
}
}
结果输出:
4、多态的弊端
提高了扩展性,但是只能试用父类的引用访问父类中的成员。
5、多态的应用
例1
/*
需求:基础班学生:学习,睡觉。
高级班学生:学习,睡觉。
思路:1.创建工具类,把它们共性内容封装进去。
2.可以将两类事物进行抽取。
*/
abstract class Student//父类
{
public abstract void study();//学习多样,不好说,抽象化
public void sleep()
{
System.out.println("睡觉");
}
}
class BaseStudent extends Student//子类继承父类
{
public void study()
{
System.out.println("base study");
}
public void sleep()//特有方法,重写
{
System.out.println("站着睡");
}
}
class AdvStudent extends Student//子类继承父类
{
public void study()
{
System.out.println("adv study");
}
}
class DoStudent//封装公共部分
{
public void dosome(Student stu)
{
stu.study();
stu.sleep();
}
}
class StudentDemo
{
public static void main(String[] args)
{
DoStudent a=new DoStudent();
a.dosome(new BaseStudent());
a.dosome(new AdvStudent());
}
}
结果输出:
例2
abstract class Animal//父类:动物
{
abstract void eat();//吃什么不好说,抽象化
}
class cat extends Animal//子类:猫 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃鱼");
}
void catchMonse()//特有属性
{
System.out.println("抓老鼠");
}
}
class dog extends Animal//子类:狗 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃骨头");
}
void keepingGuard()//特有属性
{
System.out.println("看家");
}
}
class pig extends Animal//子类:猪 继承 父类:动物
{
void eat()//共有属性
{
System.out.println("吃饲料");
}
void gongdi()//特有属性
{
System.out.println("拱地");
}
}
class AnimalDemo
{
public static void main(String[] args)
{
Animal a=new cat();//类型提升,向上转型,如:byte a=2,int b=a。a的类型提升为int型
a.eat();
//如果想要调用猫的特有方法时,如何操作?
//强制将父类的引用。转成子类类型。向下转型。
cat c=(cat)a;
c.catchMonse();
/*
千万不要出现这样的操作,就是将父类对象转成子类类型。
我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
多态自始至终都是子类对象在做着变化。
Animal a=new Animal();
cat c=(cat)a;
*/
function(new cat());
function(new dog());
function(new pig());
}
public static void function(Animal a)
{
a.eat();
if (a instanceof cat)//类型判断
{
cat c=(cat)a;
c.catchMonse();
}
else if (a instanceof dog)//类型判断
{
dog c=(dog)a;
c.keepingGuard();
}
else if(a instanceof pig)//类型判断
{
pig c=(pig)a;
c.gongdi();
}
}
}
结果输出:
6、在多态中成员函数的特点
a.在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过;如果没有编译失败。
b.在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
例1
class Fu//父类
{ void method1(){}
void method2(){}
}
class Zi extends Fu//子类继承父类
{
void method1(){}
void method3(){}
}
class Demo1
{
public static void main(String[] args)
{
Fu f=new Zi();
f.method1();
f.method2();
/*
Fu f=new Zi();
f.method1();
f.method2();
f.method3();
这样是不通过的,编译时看父类中有没有方法1,2,运行时候看子类有没有方法1,2(方法2继承父类)
*/
}
}
c.在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
无论编译和运行,都参考左边(引用型变量所属的类)。
例2
class Fu//父类
{
int num=5;//父类的成员变量
void method1(){}
void method2(){}
}
class Zi extends Fu//子类继承父类
{
int num=8;//子类的成员变量
void method1(){}
void method3(){}
}
class Demo1
{
public static void main(String[] args)
{
Fu f=new Zi();
System.out.println(f.num);
Zi z=new Zi();
System.out.println(z.num);
}
}
结果输出:
d.在多态中,静态成员函数的特点:
无论编译和运行,都参考左边。没有被覆盖的说法。
例3
class Fu//父类
{
void method1(){}
void method2(){}
static method4(){}
}
class Zi extends Fu//子类继承父类
{
void method1(){}
void method3(){}
static method4(){}
}
class Demo1
{
public static void main(String[] args)
{
Fu f=new Zi();
f.method4();//只参考左边父类
Zi z=new Zi();
z.method4();//只参考左边子类
}
}
多态的主板示例
例4
/*
需求:电脑运行实例
电脑运行基于主板
思路:1.主板有卡槽装接口,接口可以查符合型号的声卡或网卡
2.主板通过接口控制声卡与网卡的运行
*/
interface 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)//不为Null的判断
{
p.open();
p.close();
}
}
}
class NetCard implements PCI//子类实现父类
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
}
}
class VoiceCard implements PCI//子类实现父类
{
public void open()
{
System.out.println("voicecard open");
}
public void close()
{
System.out.println("voicecard close");
}
}
class duotaiDemo
{
public static void main(String[] args)
{
MainBoard mb=new MainBoard();//创建对象
mb.run();//电脑运行
mb.usePCI(new NetCard());//电脑上网
mb.usePCI(new VoiceCard());//电脑听歌
}
}
结果输出: