目录
一、多态的注意事项和细节讨论
细节讨论案例
二、java的动态绑定机制
三、多态的应用
方法或对象具有多种形态称之为多态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的
1.方法的多态:重写和重载就体现出多态
2.对象的多态:①一个对象的编译类型和运行类型可以不一致
②编译类型在定义对象时就已经确定了,不能再改变
③运行类型是可以变化的
④编译类型看定义时 = 号的左边,运行类型看 = 号的右边
什么是多态?多态的具体体现有哪些?
多态:方法或对象具有多种形态,是OOP的第三大特征,是建立在封装和继承之上的
多态具体体现:
1.方法多态
(1)重载体现多态(2)重写体现多态
2.对象多态
(1)对象的编译类型和运行类型可以不一致,编译类型在定义时就已确定,无法改变
(2)对象的运行类可以是变化的,可以通过getclass()来查看运行类型
(3)编译类型看定义时 = 号的左边,运行类型看 = 号的右边
调方法看运行类型,调属性看编译类型!!!
1.多态的前提是:两个对象(类)存在继承关系
2.多态的向上转型:①本质:父类的引用指向了子类的对象
②语法:父类类型 引用名 = new 子类类型();
③特点:编译类型看等号左边,运行类型看等号右边
可以调用父类中的所有成员(需遵守访问权限)
不能调用子类中特有成员
最终运行效果看子类的具体实现,即调用方法时从子类开始查找
3.多态的向下转型:①语法:子类类型 引用名 = (子类类型) 父类引用;
②只能强转父类的引用,不能强转父类的对象
③要求父类的引用必须指向的是当前目标类型的对象
④当向下转型后,可以调用子类类型中所有的成员
4.属性没有重写之说!属性的值看编译类型
public class PolyDetail02 {
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; //属性
}
5. instanceof 比较操作符,用于判断对象的运行类型是否为XX类型或者XX类型的子类型
instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
public class PolyDetail03 {
public static void main(String[] args) {
//instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型
BB bb = new BB();
System.out.println(bb instanceof BB); //true
System.out.println(bb instanceof AA); //true
Object obj = new Object();
System.out.println(obj instanceof AA); //false
String str = "hello";
//System.out.println(str instanceof AA); //错误的
System.out.println(str instanceof Object); //true
}
}
class AA {} //父类
class BB extends AA {} //子类
public class PolyDetail {
public static void main(String[] args) {
//向上转型:父类的引用指向了子类的对象
//语法: 父类类型 引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat(); //可以,Object 也是 Cat 的父类
//向上转型调用方法的规则如下:
//1.可以调用父类中的所有成员(需遵守访问权限),但不能调用子类中特有的成员
//2.因为在编译阶段,能调用哪些成员,是由编译类型来决定的
//animal.catchMouse(); 错误的
//3.最终运行效果看子类的具体实现,即调用方法时,按照从子类开始查找方法,然后调用,
//规则和我们前面讲的方法调用规则一致
animal.eat(); //猫吃鱼
animal.run(); //跑
animal.show(); //hello,你好
animal.sleep();//睡
//希望调用Cat的catchMouse方法
//多态的向下转型:
//1.语法: 子类类型 引用名 = (子类类型)父类引用;
//cat的编译类型是Cat,运行类型也是Cat
Cat cat = (Cat) animal;
cat.cathMouse();
//2.要求父类的引用必须指向的是当前目标类型的对象
//Dog dog = (Dog) animal; //错误的,不可以把猫对象强转成狗
}
}
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 cathMouse(){
System.out.println("猫抓老鼠");
}
}
public class Dog extends Animal {//Dog是Animal的子类
}
1.当调用对象方法时,该方法会和该对象的内存地址(运行类型)绑定
2.当调用对象属性时,没有动态绑定机制,哪里声明哪里使用(首先按作用域查找,作用域如果没有则按继承机制继续查找)
public class DynamicBinding {
public static void main(String[] args) {
//java的动态绑定机制
//1.当调用对象方法时,该方法会和该对象的内存地址(运行类型)绑定
//2.当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用(首先按作用域来找,作用域如果没有就按继承机制来找)
//a 的编译类型 A, 运行类型 B
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() {//父类 sum()
return getI() + 10;//20 + 10
}
public int sum1() {//父类 sum1()
return i + 10;//10 + 10
}
public int getI() {//父类 getI
return i;
}
}
class B extends A {//子类
//属性
public int i = 20;
//方法
// public int sum() {
// return i + 20;
// }
// public int sum1() {
// return i + 10;
// }
public int getI() {//子类 getI()
return i;
}
}
1.多态数组:数组的定义类型为父类,里面保存的实际元素类型为子类类型
public class PolyArray {
public static void main(String[] args) {
//应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student 对象
// 和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象say 方法
Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("mary", 19, 100);
persons[2] = new Student("smith", 18, 75);
persons[3] = new Teacher("scott", 30, 10000);
persons[4] = new Teacher("king", 40, 20000);
//循环遍历多态数组,调用say
for (int i = 0; i < persons.length; i++) {
//提示:person[i] 编译类型是Person,运行类型是根据实际情况由JVM机来判断
System.out.println(persons[i].say());//动态绑定机制
//使用类型判断 + 向下转型
if (persons[i] instanceof Student) { //判断person[i]的运行类型是不是Student
((Student) persons[i]).study();
} else if (persons[i] instanceof Teacher) {
((Teacher) persons[i]).teach();
}else if(persons[i] instanceof Person){
//
}else{
System.out.println("你输入的信息有误");
}
}
}
}
public class Person { //父类
//属性
private String name;
private int age;
//构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//say方法,返回名字和年龄
public String say(){
return name + "\t" +age;
}
//get和set方法
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 class Teacher extends Person { //子类
//属性
private double salary;
//构造器
public Teacher(String name, int age, double salary) {
super(name, age);
this.salary = salary;
}
//重写父类say方法
@Override
public String say() {
return super.say() + " 老师 salary=" + salary;
}
//特有的方法
public void teach(){
System.out.println("老师 " + getName() + " 正在讲java课程");
}
//get和set方法
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
public class Student extends Person { //子类
//属性
private double score;
//构造器
public Student(String name, int age, double score) {
super(name, age);
this.score = score;
}
//重写父类say方法
@Override
public String say() {
return super.say() + " 学生 score=" + score;
}
//特有的方法
public void study(){
System.out.println("学生 " + getName() + " 正在学java...");
}
//get和set方法
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
2.多态参数:方法定义的形参类型为父类类型,实参类型为子类类型
package com.learn.poly_.polyparameter;
public class PolyParameter {
public static void main(String[] args) {
Worker tom = new Worker("tom", 2500);
Manage milan = new Manage("milan", 5000, 20000);
PolyParameter polyParameter = new PolyParameter();
polyParameter.showEmpAnnual(tom);
polyParameter.showEmpAnnual(milan);
polyParameter.testWork(tom);
polyParameter.testWork(milan);
}
//showEmpAnnual(Employee e)
//实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [e.getAnnual()]
public void showEmpAnnual(Employee e){
System.out.println(e.getAnnual());//动态绑定机制
}
//添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法
public void testWork(Employee e){
if(e instanceof Worker){
((Worker) e).work(); //有一个向下转型的操作
}else if(e instanceof Manage){
((Manage) e).manage(); //有一个向下转型的操作
}else{
System.out.println("不做处理...");
}
}
}
package com.learn.poly_.polyparameter;
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
//得到年工资的方法
public double getAnnual(){
return 12 * salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
}
package com.learn.poly_.polyparameter;
public class Manage extends Employee {
private double bonus;
public Manage(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
//方法
public void manage(){
System.out.println("经理 " + getName() + "is manage");
}
//重写获取年薪方法
@Override
public double getAnnual() {
return super.getAnnual() + bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
}
package com.learn.poly_.polyparameter;
public class Worker extends Employee {
public Worker(String name, double salary) {
super(name, salary);
}
public void work(){
System.out.println("普通员工" + getName() + " is working");
}
//方法重写
@Override
public double getAnnual() { //因为普通员工没有其他收入,则直接调用父类方法
return super.getAnnual();
}
}