Java中多态的体现
多态:表示一个事物的多种表现形态,同一个事物以不同的形态表现出来。
多态体现的格式:
父类类型 变量名=new 子类对象;
变量名.方法名();
父类类型:指子类对象继承的父类类型或者实现的父类接口类型。
当使用多态的形式调用方法时,首先会检查父类中是否有这个方法,如果没有,则编译报错,如果有,则执行子类中重写后的方法。
/**
* @description: 父类
* @author: Murphy
* @date: 2020/6/233:20 上午
*/
abstract class AbstractAnimal {
public abstract void eat();
}
/**
* @description: 子类猫
* @author: Murphy
* @date: 2020/6/233:21 上午
*/
public class Cat extends AbstractAnimal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
/**
* @description: 子类狗
* @author: Murphy
* @date: 2020/6/233:22 上午
*/
public class Dog extends AbstractAnimal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
/**
* @description: 多态测试类
* @author: Murphy
* @date: 2020/6/233:23 上午
*/
public class AnimalTest {
public static void main(String[] args) {
AbstractAnimal c = new Cat();
AbstractAnimal d = new Dog();
c.eat();
d.eat();
AnimalTest animalTest = new AnimalTest();
animalTest.method(new Cat());
}
public void method(AbstractAnimal animal) {
animal.eat();
}
}
//执行结果
猫吃鱼
狗吃肉
猫吃鱼
多态的弊端
把一个子类类型提升成为了一个父类类型,那么在编译的过程中,编译器不会考虑具体是哪个子类类型,而是只根据当前的父类类型去操作,因此在调用方法的时候,会在父类中寻找有没有这个方法,如果没有则编译报错,如果有才会执行子类重写后的方法。所以,在使用多态时有一个弊端就是不能使用子类中特有的功能。
为了解决这个弊端,需要在使用子类特有功能的时候,进行类型转换。
Animal a=new Cat();//向上转型
Cat c=(Cat) a;//向下转型
无论是向上转型还是向下转型,最终都是子类对象做类型变化,跟父类对象没关系。
**向下转型有风险,使用需谨慎。**例如我们无法将猫的对象强制转化成狗的类型。因此在使用向下转型时,需要先做类型判断,此时需要使用instanceof关键字。
if (c instanceof Cat) {
Cat cat = (Cat) c;
cat.catchMouse();
}
对象名 instanceof 类型;//当对象属于类型时,返回结果为true
多态的优势
/**
* @description: 父类
* @author: Murphy
* @date: 2020/6/233:20 上午
*/
abstract class AbstractAnimal {
public abstract void eat();
}
/**
* @description: 子类猫
* @author: Murphy
* @date: 2020/6/233:21 上午
*/
public class Cat extends AbstractAnimal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
/**
* @description: 子类狗
* @author: Murphy
* @date: 2020/6/233:22 上午
*/
public class Dog extends AbstractAnimal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
/**
* @description: 多态测试类
* @author: Murphy
* @date: 2020/6/233:23 上午
*/
public class AnimalTest {
public static void main(String[] args) {
AbstractAnimal c = new Cat();
AbstractAnimal d = new Dog();
method(c);
method(c);
}
public static void method(AbstractAnimal animal) {
animal.eat();
}
}
多态的优势:可以使程序的编写更加简单,并且有良好的扩展性。
多态的典型例题
/**
* @description: B的父类
* @author: Murphy
* @date: 2020/6/2311:08 下午
*/
public class A {
public String show(D d) {
return "A and D";
}
public String show(A a) {
return "A and A";
}
}
/**
* @description: A的子类
* @author: Murphy
* @date: 2020/6/2311:10 下午
*/
public class B extends A {
public String show(B b) {
return "B and B";
}
@Override
public String show(A a) {
return "B and A";
}
}
/**
* @description: B的子类
* @author: Murphy
* @date: 2020/6/2311:12 下午
*/
public class C extends B {
}
/**
* @description: B的子类
* @author: Murphy
* @date: 2020/6/2311:13 下午
*/
public class D extends B {
}
/**
* @description: 测试类
* @author: Murphy
* @date: 2020/6/2311:14 下午
*/
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1---" + a1.show(b));
System.out.println("2---" + a1.show(c));
System.out.println("3---" + a1.show(d));
System.out.println("4---" + a2.show(b));
System.out.println("5---" + a2.show(c));
System.out.println("6---" + a2.show(d));
System.out.println("7---" + b.show(b));
System.out.println("8---" + b.show(c));
System.out.println("9---" + b.show(d));
}
}
//执行结果
1---A and A
2---A and A
3---A and D
4---B and A
5---B and A
6---A and D
7---B and B
8---B and B
9---A and D
多态中方法执行的原则:
①由子类(实现类)的类型决定调用谁的成员方法,但这有一个前提就是被调用的方法必须在父类(接口)中定义过;
②继承链中对象调用方法的优先级:this.show(O)→super.show(O)→this.show((super)O)→super.(super(O))。
以5中a2.show©为例:
1、首先根据原则②执行this.show(O),此时a2是A类的引用变量,所以此时this代表A类。根据原则①,a2会先在A类中寻找方法show(C c),如果A类中有该方法,再去看B类中是否重写了该方法,如果重写,则执行重写后的方法,如果没有重写,则执行A类中的方法。
2、但是A类中没有方法show(C c),因此接下来执行super.show(O),由于A类没有父类,因此这一步直接跳过。
3、再执行this.show((super)O),即在A类中寻找是否有方法show(B b),如果有,再去看B类中是否重写了该方法,如果重写,则执行重写后的方法,如果没有重写,则执行A类中的show(B b)方法。
4、但是A类中没有方法show(B b),因此接下来执行super.(super(O)),同样由于A类没有父类,因此这一步直接跳过。
5、重新回到第一步this.show(O),但是此时的O已经由原来的C类对象变成了B类对象,重复上述步骤可得执行结果。