1.多态(最核心的特征)
主要参考知乎这个问题 程序狗的回答 以及自己学习的一些理解
1.1 生活中的例子:
- 动物的都有会吼叫,但是每个动物都有自己的叫声
- 对于不同程序,按F1的响应式是不同,Chrome浏览器下按住F1会跳出Chrome的帮助页面,Word对应F1的响应是浏览器中的office的支持帮助文档
总结:允许不同类的对象对同一消息作出不同的响应
1.2 分类
- 编译时多态:设计时多态,编译器在编译过程中能够区分不同行为,通过方法重载实现
- 运行时多态:Java程序运行时,系统才能够调用方法实例的类型来决定具体调用哪个方法,默认是多态的狭义定义
1.3 多态存在的三个必要条件:
- 继承
- 重写
- 父类引用指向子类对象
Parent p = new Child()
2.代码说明:
父类 Animal.java:name month 属性,run() 和 static say()
package com.imooc.animal;
// abstract 设置抽象类后,不能实例化,但是可以向上转型,指向子类实例
public class Animal {
private String name;
private int month;
public Animal(){}
public Animal(String name,int month) {
this.setName(name);
this.setMonth(month);
}
// getter and setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
// 吃东西的方法
public void eat() {
System.out.println("动物都有吃东西的能力");
}
//打招呼的方法
public static void say() {
System.out.println("小动物之间打招呼");
}
}
子类 Cat.java:猫类继承动物类,重写了eat()方法,并有独有的体重属性和普通方法 run()以及静态方法 say
package com.imooc.animal;
public class Cat extends Animal{
//属性:体重
private double weight;
public Cat() {}
public Cat(String name,int month,double weight) {
super(name,month);
this.weight=weight;
}
//方法:跑动
public void run() {
System.out.println("小猫快跑");
}
//方法:吃东西(重写父类方法)
@Override
public void eat() {
System.out.println("猫吃鱼~~~!");
}
//say() 是 Cat类独有的静态的方法,与Animal父类的say()不构成重写关系,
//因此不能加 @Override注解符
public static void say() {
System.out.println("小猫碰胡须");
}
}
子类 Dog.java:继承Animal ,重写eat() 独有 sex属性和sleep()方法
package com.imooc.animal;
public class Dog extends Animal {
//属性:性别
private String sex;
public Dog() {}
public Dog(String name,int month,String sex) {
super(name ,month);
this.sex =sex ;
}
//方法:睡觉
public void sleep() {
System.out.println("小狗有午睡的习惯");
}
//方法:吃东西(重写父方法)
@Override
public void eat() {
System.out.println("狗吃肉~~~!");
}
}
TestDemo.java
package com.imooc.animal;
public class Test {
public static void main(String[] args) {
Animal animal=new Animal();
//向上转型,自动转型,子类转父类
Animal cat=new Cat(); //父类引用指向子类对象
Animal dog=new Dog(); //父类引用指向子类对象
animal.eat(); // 动物都有吃东西的能力
cat.eat(); // 猫吃鱼~~~!
dog.eat(); // 狗吃肉~~~!
cat.say();// == Animal.say() 小动物间打招呼
cat.setName("kitty");
System.out.println(cat.getName());
// cat.run() dog.sleep() 无法调用
/**
*1.向上转型后只能调用父类的派生方法如setName、静态方法以及子类重写的方法,子类特有的无法调用
注意:父类静态方法无法被子类重写,因此向上转型后只能调用父类静态方法
*/
System.out.println("=========================");
//如果想要调用 子类特有的成员属性和方法怎么办呢? 再转回来
/**
* 向下转型(强制转型),子类引用指向父类对象,必须强转
* 可以调用子类特有的方法
*/
Cat re_cat = (Cat) cat;
re_cat.run();
re_cat.eat();
Dog re_dog = (Dog) dog;
re_dog.sleep();
re_dog.eat();
System.out.println("====================");
/**
* 在强转的过程中,转换的右边即父类对象一定是之前经过向上转型得到的,原本就是子类对象,必须满足这个强转条件
* instanceof 可以帮助判断 左边对象是否满足右边类的特性,是 就可以强转,下面重写上面 强转代码
*/
if(cat instanceof Cat) {
Cat re_cat2 = (Cat) cat;
re_cat2.run();
re_cat2.eat();
re_cat2.say(); // 小猫碰胡须,调用的是 Cat子类独有的 static say()方法 }
if(dog instanceof Dog) {
Dog re_dog2 = (Dog) dog;
re_dog2.sleep();
re_dog2.eat();
}
if(animal instanceof Cat) {
Cat animal_cat = (Cat) animal;
} else {
System.out.println("animal不是Cat类");
}
}
}
3.多态的实际应用
判断适合养什么宠物
Master.java
package com.imooc.animal;
public class Master {
/**
* 喂宠物
* 喂猫猫:吃完东西后,主人会带着去玩线球
* 喂狗狗:吃完东西后,主人会带着狗狗去睡觉
* 养兔子、鹦鹉、乌龟
*/
public void feed(Animal obj) {
if(obj instanceof Cat) {
Cat temp=(Cat) obj;
temp.eat();
temp.run();
} else if(obj instanceof Dog) {
Dog temp2=(Dog) obj;
temp2.eat();
temp2.sleep();
}
}
/**
* 饲养何种动物
* 空闲时间多:养狗
* 空闲时间少:养猫
*/
public Animal raise(boolean isManyTime) {
if(isManyTime) {
System.out.println("主人时间多,适合养狗");
return new Dog();
}else{
System.out.println("主人时间少,适合养猫");
return new Cat();
}
}
}
MasterTest.java
package com.imooc.animal;
public class MasterTest {
public static void main(String[] args) {
Master master=new Master();
Cat cat=new Cat();
Dog dog=new Dog();
master.feed(cat); //keypoint
master.feed(dog);//keypoint
System.out.println("================");
boolean isManyTime=true;
Animal temp=master.raise(isManyTime);
}
}