方法或对象具有多种形态,是面向对象的三大特征,多态是建立在封装和继承之上的
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 ,运行类型是Dog
Animal 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 运行类型也是Cat
cat.catchMouse();//可以调用子类里面的特有方法
}
}
3、属性没有重写,属性的值看编译类型
package com.javase.poly_.detail_;
public class PolyDetail01 {
public static void main(String[] args) {
//编译类型是Base 运行类型是 Sun
Base b = new Sun();
System.out.println(b.n1);//属性的值看编译类型,结果为10
Sun 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);//true
System.out.println(bb instanceof AA);//true
//用于判断对象的运行类型是否为某个类型或某个类型的子类型
//编译类型AA 运行类型BB
AA aa = new BB();
System.out.println(aa instanceof AA);//true
System.out.println(aa instanceof BB);//true
Object 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.4
int in = 5;//正确
boolean b = (boolean) in;//错误,boolean不能转换成int类型
Object obj = "hello";//正确 向上转型
String objStr = (String) obj;//正确 向下转型
System.out.println(objStr);//hello
Object objPri = new Integer(5);//正确 向上转型
String str = (String) objPri;//错误 指向Integer的父类引用,转成String
Integer str1 = (Integer) objPri;//正确 向下转型
}
}
输出:
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 -> 30
System.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;
}
}
数组的定义类型为父类类型,里面保存的实际元素类型为子类型。
案例演示:
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();
}
}
}
}
方法定义的形参类型为父类类型,实参类型允许为子类型
案例演示:
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();
}
}
}