代码复用性不高,而且不利于维护
解决方案:引出多态
多态(多种状态)基本介绍
方法或对象具有多种形态。是面对对象的第三大特征,多态是建立在封装和继承基础之上的。
多态的具体体现
1.方法的多态
A a = new A();//方法的重载体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sun(10, 30, 50));
B b = new B(); // A extends B 方法的重写体现多态
System.out.println(b.say("Hello"));
A objs = new A();
System.out.println(objs.say("ok"));
2.对象的多态(核心、困难、重点)
重要的几句话:
(1)一个对象的编译类型和运行类型可以不一致
(2)编译类型在定义对象时,就确认了,不能改变
(3)运行类型是可以变化的
(4)编译类型看定义时 = 号的左边,运行类型看 = 号的右边
Animal animal = new Dog();//animal编译类型是Animal,运行类型是Dog
animal = new Cat();//animal的运行类型变成了Cat,编译类型仍然是Animal
public class Animal {
public void cry() {
System.out.println("Animal动物在叫...");
}
}
public class Cat extends Animal {
public void cry() {
System.out.println("Cat cry() 小猫喵喵叫...");
}
}
public class Dog extends Animal {
public void cry() {
System.out.println("Dog cry() 小狗汪汪叫...");
}
}
public class TestPoly {
public static void main(String[] args) {
//体验对象多态的特点
//animal编译类型就是Animal,运行类型Dog
Animal animal = new Dog();
//因为运行时,执行到改行时,animal运行类型是Dog,所以cry就是Dog的cry
animal.cry();//小狗汪汪叫...
//animal编译类型Animal,运行类型就是Cat
animal = new Cat();
animal.cry();//小猫喵喵叫...
}
}
多态的注意事项和细节讨论
多态的前提是:两个对象(类)存在继承关系
多态的向上转型
1)本质:父类的引用指向了子类的对象
2)语法:父类类型 引用名 = new 子类类型();
3)特点: 编译类型看左边,运行类型看右边。
可以调用父类中的所有成员(需遵守访问权限);
不能调用子类中特有成员;(因为在编译阶段,能调用哪些成员,是由编译类型来决定的)
故:animal().catchMouse(); 错误
最终运行结果看子类(运行类型)的具体实现!即调用方法时,按照从子类(运行类型)开始查找方法
public class Animal {
String name = "动物";
int age = 10;
public void sleep(){
System.out.println("睡");
}
public void run(){
System.out.println("跑");
}
public void eat(){
System.out.println("吃");
}
public void show(){
System.out.println("Hello,你好!");
}
}
public class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
public class PolyDetail {
public static void main (String[] args) {
Animal animal = new Cat();
animal.eat();//猫吃鱼
animal.run();//跑
animal.show();//Hello,你好
animal.sleep();//睡
}
}
多态的向下转型
1)语法:子类类型 引用名 = (子类类型)父类引用;
2)只能强转父类的引用,不能强转父类的对象
3)要求父类的引用必须指向的是当前目标类型的对象
4)当向下转型后,可以调用子类类型中的所有成员
Cat cat = (Cat) animal; //animal之前指向Cat,向下转型只能转为Cat
cat.catchMouse();猫抓老鼠
属性没有重写之说!属性的值看编译类型
public class Test {
public static void main (String[] args) {
Base base = new Sub();
System..out.println(base.count);//10
Sub sub = new Sub();
System.out.println(sub.count);//20
}
}
class Base {
int count = 10;
}
class Sub extends Base {
int count = 20;
}
instanceof比较操作符,用于判断对象的运行类型是否为XX类型或XX的子类型
public class Test {
public static void main (String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB); //true
System.out.println(bb instanceof AA); //true
AA aa = new BB();
System.out.println(aa instanceof AA); //true
System.out.println(aa instanceof AA); //true
Object obj = new Object();
System.out.println(obj instanceof AA); //false
String str = "Hello";
System.out.println(str instanceof AA); //error
System.out.println(str instanceof Object); //true
}
}
class AA {} //父类
class BB extends AA {} //子类
Java的动态绑定机制(非常非常非常重要。)
class A {
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum1() {
return i + 10;
}
public int getI() {
return i;
}
}
class B extends A {
public int i = 20;
public int sum() {
return i + 20;
}
public int getI() {
return i;
}
public int sum1() {
return i + 10;
}
}
//main方法
A a = new B(); //向上转型
System.out.println(a.sum()); //40 -> 30 当把B类中的sum()注释掉后
System.out.println(a.sum1()); //30 -> 20 当把B类中的sum1()注释掉后
多态的应用
1)多态数组:数组定义类型为父类类型,里面保存的实际元素类型为子类类型
2)多态参数:方法定义的形参类型为父类类型,实参类型允许为子类类型