多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,大概像什么呢?比如说一个人有开车的技能,一般而言就四人的车来说,有不同品牌的,每个车的性能不同,但是这个人掌握了开车的技能,我们就认为它既能开出租车拉人,也能开面包车拉商品,也能开小货车拉货物。
多态构成的3个必要条件
- 继承
- 重写
- 父类引用指向子类对象
多态的优点:
消除类型之间的耦合,可扩充性,灵活性
示例,
父类Animal:
public class Animal {
//私有属性
private String name;
private int age;
//属性
public String color="Grey";
//无参构造器
public Animal() {
System.out.println("Animal's non parameter constructor");
}
//有参构造器
public Animal(String name,int age,String color) {
this.name=name;
this.age=age;
this.color=color;
System.out.println("Animal's parameter constructor");
}
//吃方法
public void eat() {
System.out.println(" Animal is eating");
}
//睡方法
public void sleep() {
System.out.println("Animal is sleeping");
}
//看方法
private void watch() {
System.out.println("Animal is watching");
}
}
子类1Sheep:
public class Sheep extends Animal {
String color="white";
//重写父类Animal的方法
public void eat() {
System.out.println("Sheep is eating glass");
}
//重写父类Animal的方法
public void sleep() {
System.out.println("Sheep is sleeping ");
}
//添加的父类没有的方法
public void drink() {
System.out.println("Sleep is drinking water");
}
}
子类2Tiger:
public class Tiger extends Animal {
String color="red";
//重写父类Animal的方法
public void eat() {
System.out.println("Tiger is eating meat");
}
//重写父类Animal的方法
public void sleep() {
System.out.println("Tiger is sleeping ");
}
}
测试类:
public class PolymorphicTest {
public static void main(String[] args) {
Animal a=new Tiger();
//a是父类对象的引用,指向的时子类对象new Tiger,这是三个必要条件之一的父类引用指向子类对象
//实现了子类类型向父类类型转换,叫做向上转型,自动类型转换
a.sleep();
System.out.println("a's color is "+a.color);//输出位Grey,说明变量没有被重写
Animal b=new Sheep();
b.eat();
// b.drink();b是Animal对象,没有drink方法
//父类类型向子类类型转换,叫向下转型,强制类型转换,然后就可以访问子类中的新添加方法
了。
Sheep c=(Sheep)b;
c.drink();
}
}
out:
Animal's non parameter constructor//调用构造方法时打印的,无需理会
Tiger is sleeping
a's color is Grey
Animal's non parameter constructor//调用构造方法时打印的,无需理会
Sheep is eating glass
Sleep is drinking water
静态绑定和动态绑定
在上述代码的测试类中,程序在编译的过程中,a对象被看成时Animal类型的,所以a.sleep()绑定的是Animal类的sleep方法,叫做静态绑定,程序运行时,a指向堆内存中的Tiger对象,而在Tiger中对sleep方法进行了重写,所以在运行时,程序绑定的时Tiger中的sleep方法,叫做动态绑定,a的类型还是父类Animal的引用,不能访问子类Tiger中其他方法(不是对父类重写的方法)。
强制类型转换和自动类型转换
子类向父类型进行转换,是自动类型转换,也叫做向上转型。还有一种情况是父类向子类型转换,是强制类型转换,也叫向下转型。
instanceof 关键字,用来测试一个对象是否为一个类的实例,用法为:
boolean result = obj instanceof class
中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
强制类型转换时,可以用instanceof判断前者对象是否属于后者类,如果是才可以转换,如果不是,则不能转换,否则会报出ClassCastException异常。
如下:
public class PolymorphicTest {
public static void main(String[] args) {
Animal a=new Tiger();
a.sleep();
System.out.println("a's color is "+a.color);
Animal b=new Sheep();
b.eat();
//如果想要执行Sheep类中的drink方法,就需要将b强制转换成Sheep类
// Sheep d=(Sheep)a;//报错,class Tiger cannot be cast to class Sheep
//所以在强制类型转换之前,加个判断
if (b instanceof Sheep) {
Sheep c=(Sheep)b;
c.drink();
}else {
System.out.println("connot convert Animal to Sheep");
}
}
}
多态的例子:
父类Mediaplayer,有一个playVideo的方法:
public class MediaPlayer {
public void playVideo() {
System.out.println("MediaPlayer is playing video");
}
}
子类MobilePhone重写了父类的playVideo方法:
public class MobilePhone extends MediaPlayer {
public void playVideo() {
System.out.println("the mobilephone is playing video on internet");
}
}
子类Laptop重写了父类的playVideo方法:
public class Laptop extends MediaPlayer {
public void playVideo() {
System.out.println("the notebook is playing vedio about humor");
}
}
类Person,有个watchTv的方法,调用了Mediaplayer的playVideo方法:
public class Person {
private int age;
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return this.age;
}
//创建watchTv方法,参数位MediaPlayer类
public void watchTv( MediaPlayer m) {
m.playVideo();
}
}
测试类:
public class PolymorphicTest {
public static void main(String[] args) {
Person p=new Person();
MediaPlayer m =new MobilePhone();
//传入的参数是MediaPlayer类型的,调用的时候动态绑定到子类MobilePhone的playVideo方法
p.watchTv(m);
MediaPlayer m0=new Laptop();
p.watchTv(m0);
//传入的参数是MediaPlayer类型的,调用的时候动态绑定到子类Laptop的playVideo方法
}
}