1.多态概述
同一个对象,在不同时刻表现出来的不同形态。
多态的前提和体现
- 有继承/实现关系
- 有方法重写
- 有父类引用指向子类对象
2.多态中成员访问特点
- 成员变量:编译看左边,执行看左边
- 成员方法:编译看左边,执行看右边
为啥成员变量和成员方法的访问不一样?
- 因为成员方法有重写,而成员变量没有
Animal.java
public class Animal {
public int age=40;
public void eat(){
System.out.println("动物吃东西");
}
}
Cat.java
public class Cat extends Animal{
public int age=20;
public int weight=10;
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void playGame(){
System.out.println("猫捉迷藏");
}
}
AnimalDemo.java
public class AnimalDemo {
public static void main(String[] args) {
Animal a=new Cat();//父类引用指向子类对象
System.out.println(a.age);//40
// System.out.println(a.weight);
a.eat();//猫吃鱼
// a.playGame();
}
}
3.多态的好处和弊端
好处:提高了程序的可扩展性
- 具体实现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。
弊端:不能使用子类特有的功能
- 因为编译看左边,父类中没有子类特有的功能,编译这关就不通过。
Animal.java
package com.ydh_02;
public class Animal {
public void eat(){
System.out.println("动物吃东西");
}
}
Cat.java
package com.ydh_02;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
Dog.java
package com.ydh_02;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void lookDoor(){
System.out.println("狗看门");
}
}
AnimalOperator.java
package com.ydh_02;
/*
动物操作类
* */
public class AnimalOperator {
/*
public void useAnimal(Cat c){//Cat c=new Cat()
c.eat();
}
//方法重载,不会报错
public void useAnimal(Dog d){//Dog d = new Dog();
d.eat();
}
*/
public void useAnimal(Animal a){
//Animal a=new Cat()
//Animal a=new Dog()
a.eat();
// a.lookDoor();//编译不通过,因为编译看左边
}
}
AnimalDemo.java
package com.ydh_02;
public class AnimalDemo {
public static void main(String[] args) {
//创建动物操作类的对象,调用方法
AnimalOperator ao=new AnimalOperator();
Cat c=new Cat();
ao.useAnimal(c);//猫吃鱼
Dog d = new Dog();
ao.useAnimal(d);//狗吃骨头
}
}
4.多态中的转型
向上转型
- 从子到父
- 父类引用指向子类对象
向下转型
- 从父到子
- 父类引用转为子类对象
注意:
- 对象的向下转型解决了多态中的弊端(不能使用子类特有的功能)。
- 同类之间不能发生转换,否则会抛出ClassCastException类型转换异常。
Animal.java
package com.ydh_03;
public class Animal {
public void eat(){
System.out.println("动物吃东西");
}
}
Cat.java
package com.ydh_03;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void playGame(){
System.out.println("猫捉迷藏");
}
}
AnimalDemo.java
package com.ydh_03;
public class AnimalDemo {
public static void main(String[] args) {
Animal a=new Cat();//向上转型,父类引用指向子类对象
a.eat();//猫吃鱼
// a.playGame();
/*
Cat c=new Cat();
c.eat();
c.playGame();
*/
Cat c = (Cat) a;//向下转型,父类引用转为子类对象
c.eat();//猫吃鱼
c.playGame();//猫捉迷藏
//假设我们额外定义了一个Dog类,测试同类之间是否能转换
// Dog d=(Dog) c;//ClassCastException类型转换异常
}
}
5.案例:猫和狗(多态版)
Animal.java
package com.ydh_04;
public class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("动物吃东西");
}
}
Cat.java
package com.ydh_04;
public class Cat extends Animal{
public Cat() {
}
public Cat(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
Dog.java
package com.ydh_04;
public class Dog extends Animal{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
AnimalDemo.java
package com.ydh_04;
public class AnimalDemo {
public static void main(String[] args) {
Animal a=new Cat();
a.setName("加菲");
a.setAge(5);
System.out.println(a.getName()+","+a.getAge());
a.eat();
a=new Cat("加菲",5);
System.out.println(a.getName()+","+a.getAge());
a.eat();
Animal a2=new Dog();
a2.setName("小七");
a2.setAge(3);
System.out.println(a2.getName()+","+a2.getAge());
a2.eat();
a2=new Dog("小七",3);
System.out.println(a2.getName()+","+a2.getAge());
a2.eat();
}
}