一、基本介绍
方法或对象具有多种形态,是面向对象的三大特征,多态是建立在封装和继承之上的
二、多态的具体体现
1、方法的多态:
重写和重载就体现多态
案例演示:
package com.javase.poly_;public class PloyMethod {public static void main(String[] args) {//方法重载体现多态A a = new A();//我们传入不同的参数,调用不同的方法System.out.println(a.sum(10, 20));System.out.println(a.sum(10, 20, 30));//方法重写体现多态B b = new B();a.say();b.say();//虽然是同一方法,但根据对象不一样调用结果是不一样的。}
}class B {//父类public void say() {System.out.println("B say 方法被调用...");}
}class A extends B {//子类public int sum(int n1, int n2) {return n1 + n2;}public int sum(int n1, int n2, int n3) {return n1 + n2 + n3;}public void say() {System.out.println("A say 方法被调用...");}
}
2、对象的多态
1.一个对象的编译类型和运行类型可以不一致。
2.编译类型在定义对象时,就确定了,不能改变
3.运行类型是可以变化的。
4.编译类型看定义时 = 号的左边,运行类型看 = 号的右边。
案例演示:
Animal类
package com.javase.poly_.objectpoly_;public class Animal {public void cry() {System.out.println("动物叫...");}
}
Dog类:
package com.javase.poly_.objectpoly_;public class Dog extends Animal{public void cry() {System.out.println("小狗汪汪叫...");}
}
Cat类:
package com.javase.poly_.objectpoly_;import com.javase.super_.A;public class Cat extends Animal {public void cry() {System.out.println("小猫喵喵叫...");}
}
输出:
package com.javase.poly_.objectpoly_;public class PolyObject {public static void main(String[] args) {//animal编译类型是 Animal ,运行类型是DogAnimal animal = new Dog();animal.cry();//因为animal运行类型是Dog,所以会调用Dog里面的cry方法animal = new Cat();animal.cry();//因为animal运行类型变成了Cat,所以会调用Cat里面的cry方法}
}
三、多态的注意事项和细节讨论
多态的前提是:两个对象(类)存在继承关系。
1、多态的向上转型
本质上,父类的引用指向了子类对象。
在语法上:父类类型 引用名 = new 子类类型();
编译类型看左边,运行类型看右边,可以调用父类中的所有成员,但必须遵守访问权限,不能调用子类中特有成员,最终运行效果看子类的具体实现。
案例演示:
package com.javase.poly_.detail_;public class Animal {public void eat() {System.out.println("吃");}public void run() {System.out.println("跑");}
}
package com.javase.poly_.detail_;public class Cat extends Animal {public void eat() {//方法重写System.out.println("猫吃鱼");}public void catchMouse() {//特有方法System.out.println("猫抓老鼠");}
}
输出:
package com.javase.poly_.detail_;public class PolyDetail {public static void main(String[] args) {Animal animal = new Cat();Object obj = new Cat();//Object也是Cat父类//最终运行效果看子类的具体实现,即调用方法时,从子类开始查找方法animal.eat();//猫吃鱼animal.run();//跑}
}
2、 多态的向下转型
在语法上:子类类型 引用名 = (子类类型)父类引用
只能强转父类引用,不能强转父类对象
要求父类的引用必须指向的是当前目标类型的对象
当向下转型后,可以调用子类类型中所有的成员
案例演示:
package com.javase.poly_.detail_;public class Animal {public void eat() {System.out.println("吃");}public void run() {System.out.println("跑");}
}
package com.javase.poly_.detail_;public class Cat extends Animal {public void eat() {//方法重写System.out.println("猫吃鱼");}public void catchMouse() {//特有方法System.out.println("猫抓老鼠");}
}
输出
package com.javase.poly_.detail_;public class PolyDetail {public static void main(String[] args) {Animal animal = new Cat();//多态的向下转型Cat cat = (Cat) animal;//编译类型是Cat 运行类型也是Catcat.catchMouse();//可以调用子类里面的特有方法}
}
3、属性没有重写,属性的值看编译类型
package com.javase.poly_.detail_;public class PolyDetail01 {public static void main(String[] args) {//编译类型是Base 运行类型是 SunBase b = new Sun();System.out.println(b.n1);//属性的值看编译类型,结果为10Sun sun = new Sun();System.out.println(sun.n1);//20}
}class Base {int n1 = 10;
}class Sun extends Base {int n1 = 20;
}
4、instanceOf比较操作符,用于判断对象的运行类型是否为某个类型或某个类型的子类型。
package com.javase.poly_.detail_;public class PolyDetail02 {public static void main(String[] args) {BB bb = new BB();System.out.println(bb instanceof BB);//trueSystem.out.println(bb instanceof AA);//true//用于判断对象的运行类型是否为某个类型或某个类型的子类型//编译类型AA 运行类型BBAA aa = new BB();System.out.println(aa instanceof AA);//trueSystem.out.println(aa instanceof BB);//trueObject o = new Object();System.out.println(o instanceof AA);//false}
}class AA{}class BB extends AA {
}
四、入门练习
1.请说出下面的每条语音,哪些是正确的,哪些是错误的,为什么?
package com.javase.poly_.exercise_;public class PolyExercise01 {public static void main(String[] args) {double d = 13.4;//正确long l = (long) d;//正确System.out.println(l);//13.4int in = 5;//正确boolean b = (boolean) in;//错误,boolean不能转换成int类型Object obj = "hello";//正确 向上转型String objStr = (String) obj;//正确 向下转型System.out.println(objStr);//helloObject objPri = new Integer(5);//正确 向上转型String str = (String) objPri;//错误 指向Integer的父类引用,转成StringInteger str1 = (Integer) objPri;//正确 向下转型}
}
2.输出结果是什么:
输出:
20
20
true
10
20
五、动态绑定机制
1、当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
2、当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。
package com.javase.poly_.dynamic_;public class DynamicBinding {public static void main(String[] args) {A a = new B();System.out.println(a.sum());//40 -> 30System.out.println(a.sum1());//30 -> 20}
}class A {public int i = 10;//动态绑定机制public int sum() {//调用的子类B的getl()return getl() + 10;}public int sum1() {//当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。return i + 10;}public int getl() {return i;}
}class B extends A {public int i = 20;// public int sum() {
// return i + 20;
// }
// public int sum1() {
// return i + 10;
// }public int getl() {return i;}
}
六、多态的应用
1、多态数组
数组的定义类型为父类类型,里面保存的实际元素类型为子类型。
案例演示:
Person类
package com.javase.poly_.polyarr_;public class Person {private String name;private int age;public Person(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 String say() {return "name=" + name + " age=" + age;}
}
Student 类
package com.javase.poly_.polyarr_;public class Student extends Person {private double score;public Student(String name, int age, double score) {super(name, age);this.score = score;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}public String say() {return super.say() + " 成绩=" + score;}
}
Teacher类
package com.javase.poly_.polyarr_;public class Teacher extends Person {private double salary;public Teacher(String name, int age, double salary) {super(name, age);this.salary = salary;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public String say() {return super.say() + " 薪水=" + salary;}
}
输出:
package com.javase.poly_.polyarr_;public class PolyArray {public static void main(String[] args) {Person[] persons = new Person[5];persons[0] = new Person("张三", 20);persons[1] = new Student("李四", 15, 79.5);persons[2] = new Student("王五", 16, 60.0);persons[3] = new Teacher("铁蛋", 25, 30000);persons[4] = new Teacher("二丫", 30, 60000);for (int i = 0; i < persons.length; i++) {//编译类型是Person 运行类型是根据实际情况由JVM来判断System.out.println(persons[i].say());//多态绑定机制}}
}
如何在多态数组中调用子类特有的方法:
在Teacher类 新增特有的方法
public void teach() {System.out.println("老师 " + getName() + " 正在讲课...");
}
在Student类 新增特有的方法
public void study() {System.out.println("学生 " + getName() + "正在听课...");
}
输出:
package com.javase.poly_.polyarr_;public class PolyArray {public static void main(String[] args) {Person[] persons = new Person[5];persons[0] = new Person("张三", 20);persons[1] = new Student("李四", 15, 79.5);persons[2] = new Student("王五", 16, 60.0);persons[3] = new Teacher("铁蛋", 25, 30000);persons[4] = new Teacher("二丫", 30, 60000);for (int i = 0; i < persons.length; i++) {//编译类型是Person 运行类型是根据实际情况由JVM来判断System.out.println(persons[i].say());//多态绑定机制//使用instanceof 判断 persons[i] 是不是Student类型if(persons[i] instanceof Student) {
// Student student = ;//向下转型
// student.study();//调用子类特有方法((Student) persons[i]).study();}else if(persons[i] instanceof Teacher) {((Teacher) persons[i]).teach();}}}
}
2、多态参数
方法定义的形参类型为父类类型,实参类型允许为子类型
案例演示:
Employee类
package com.javase.poly_.polyparameter;public class Employee {private String name;private double sal;public Employee(String name, double sal) {this.name = name;this.sal = sal;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSal() {return sal;}public void setSal(double sal) {this.sal = sal;}//计算年工资public double getAnnual() {return sal * 12;}
}
Worker类
package com.javase.poly_.polyparameter;public class Worker extends Employee{public Worker(String name, double sal) {super(name, sal);}//子类特有方法public void work() {System.out.println("普通员工 " + getName() + " 正在工作...");}//共有方法public double getAnnual() {return super.getAnnual();}
}
Manager类
package com.javase.poly_.polyparameter;public class Manager extends Employee{private double bonus;public Manager(String name, double sal, double bonus) {super(name, sal);this.bonus = bonus;}public double getBonus() {return bonus;}public void setBonus(double bonus) {this.bonus = bonus;}//子类特有方法public void manage() {System.out.println("经理 " + getName() + " 正在管理员工...");}//共有方法public double getAnnual() {return super.getAnnual() + bonus;}
}
输出:
package com.javase.poly_.polyparameter;public class PolyParameter {public static void main(String[] args) {Worker zs = new Worker("张三", 2000);Manager ls = new Manager("李四", 5000, 1000);PolyParameter polyParameter = new PolyParameter();polyParameter.showEmpAnnual(zs);polyParameter.showEmpAnnual(ls);polyParameter.test(zs);polyParameter.test(ls);}//获取员工的年薪public void showEmpAnnual(Employee e) {System.out.println(e.getAnnual());}public void test(Employee e) {if(e instanceof Worker) {//判断对象类型((Worker) e).work();//向下转型}else if(e instanceof Manager) {((Manager) e).manage();}}
}