面向对象之多态

一,先引入一个问题

  请先写一个程序,食物food 可以有多种  ,鱼 骨头 米饭  ,动物也又多种,狗 猫  鱼 ,Master类中有一个feel喂食方法,接下来用传统方式解决这个问题

    问题是代码复用性不高,不利于维护   由此会引出多态  废话不多说  上代码 

    

public class Animal {
    private String name;
//构造器  get set方法
}
//========================================
public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}
//================================

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}
//============================
public class Food {
    private String name;//构造器  get set 方法
}
//=============================
public class Fish extends Food{
    public Fish(String name) {
        super(name);
    }
}
//=================================
public class Bone extends Food {
    public Bone(String name) {
        super(name);
    }
}
//================================
public class Master {
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

     public void feel(Cat cat,Fish fish){
        System.out.println("主人" + getName() + "给"+cat.getName()+"喂食"+fish.getName());
    }
    public void feel(Dog dog, Bone bone){
        System.out.println("主人" + getName() + "给"+dog.getName()+"喂食"+dog.getName());
    }
}
//================================
public class Test {
    public static void main(String[] args) {
        Master master = new Master("阿文");
        Cat cat = new Cat("小黄猫");
        Fish fish = new Fish("鱼");
        master.feel(cat,fish);

        Dog dog = new Dog("小黄狗");
        Bone bone = new Bone("骨头");
        master.feel(dog,bone);

    }
}

使用多态机制,可以统一的管理主人喂食的问题   动物有很多 ,食物有很多 不利于维护 所以引出多态

animal  编译类型是 Animal,可以指向(接收)Animal 子类的对象

food  编译类型是 Food ,可以指向(接收) Food 子类的对象

 

public void feed(Animal animal, Food food) {

 

    System.out.println("主人 " + name + "   " + animal.getName() + "   " + food.getName());     

 }

 

二, 多态的基本介绍

  方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的

    方法的重载和重写就体现出了多态 ,废话不多说上代码

  

public class PloyMethod {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.sum(2, 3));
        System.out.println(a.sum(3, 4, 5));//调用不同的构造器体体现出重载的多态
        B b = new B();
        b.say();
        a.say();//方法的重写  体现出了多态
    }
}
class B { //父类
    public void say() {
        System.out.println("B say()  方法被调用...");
    }
}
class A extends B {//子类

    public int sum(int n1, int n2) {//和下面 sum  构成重载
        return n1 + n2;
    }

    public int sum(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }

    @Override
    public void say() {
        System.out.println("a say() 方法被调用了");
    }
}

三 , 对象的多态  (重点难点)

  1>背记的重要知识点

        1)一个对象的编译和运行类型可以不一致

        2)编译类型在定义对象时就确定了,不能改变

        3)运行类型是可以改变的

       4)编译看左边 ,运行看右边

    

public class Animal {
    public void cry(){
        System.out.println("动物在叫");
    }
}
//-------------------------------------------------------
public class Cat extends Animal {
    @Override
    public void cry() {
        System.out.println("喵咪~~~~~~");
    }
}
//----------------------------------------------
public class Dog extends Animal{
    @Override
    public void cry() {
        System.out.println("汪汪~~~~~");
    }
}
//============================
public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();//        编译看左边  运行看右边
        animal.cry();//汪汪~~~~~
        animal= new Cat();
        animal.cry();//喵咪~~~~~~
    }
}

四 , 多态注意事项和细节讨论

  多态的前提是:两个对象(类)存在继承关系

   1)多态的向上转型

      1>本质:父类的引用指向子类的对象

      2>语法: 父类类型  引用名 = new  子类类型();

      3)特点: 编译类型看左边,运行类型看右边 

          可以调用父类种的所有成员(须遵守访问权限),不能调用子类中特有成员 ,最终运行效果看子类的具体实现

   2)多态的向下转型

      1>语法 : 子类类型  引用名 = (子类类型)父类引用;

      2>只能强转父类的引用 , 不能强转父类的对象

      3>要求父类的引用必须指向当前目标的对象

      4>当向下转型后,可以调用子类类型中所有的成员 

 

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 {
    String name = "小猫";
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat 特有方法
        System.out.println("猫抓老鼠");
    }
}
//====================================
public class Test {
    public static void main(String[] args) {
      Animal animal = new Cat();//向上转型  父类的引用指向子类的对象
      animal.eat(); //向上转型的调用规则  调用父类中的所有成员 遵循访问规则,
      animal.show();// 不能调用子类特有的成员,因为在编译阶段,能调用哪些成员,是由编译类型来决定的
      animal.sleep();//animal.catchMouse();错误
      animal.show();//最终运行效果看子类(运行类型)的具体实现,
        // 即调用方法时,按照从子类(运行类型)开始查找方法 ,然后调用,规则我前面我们讲的方法调用规则一致。
      //怎么调用  animal.catchMouse();   向下转型
      Cat cat = (Cat) animal;  //子类类型  引用名 = (子类类型)父类引用;
      cat.catchMouse();//要求父类的引用必须指向的是当前目标类型的对象 我的理解是先向上转型 再向下转型
      System.out.println(animal.name); //属性的调用 看编译类型  ==== 动物
      System.out.println(cat.name);  //小猫
    }
}

属性的调用  ,看编译的类型  废话不多说  上代码

public class PolyDetail02 {
    public static void main(String[] args) {
        Sub sub = new Sub();//   向上转型  属性的值看编译类型  
        System.out.println(sub.count); //20
        Base base = new Sub();
        System.out.println(base.count); //10
    }
}
class Base { //父类
    int count = 10;//属性
}
class Sub extends Base {//子类
    int count = 20;//属性
}

小知识点       instanceOf  比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型

 

public class PolyDetail03 {
    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();//aa  编译类型 AA,  运行类型是 BB  //BB 是 AA 子类
        System.out.println(aa instanceof AA);// true
        System.out.println(aa instanceof BB);// true
        Object obj = new Object();
        System.out.println(obj instanceof AA);//false
        String str = "hello";
        System.out.println(str instanceof Object);//true
    }
}
class AA{}
class BB extends AA{}

 五 , java的动态绑定机制

  1.当调用对象方法的时候,该方法会和对象的内存地址/运行类型绑定

  2.当调用对象属性时,没有动态绑定机制,哪里调用哪里使用

public class DynamicBinding {
    public static void main(String[] args) {
        A a = new B();//向上转型   //a  的编译类型 A,  运行类型 B
        System.out.println(a.sum());//会调用子类的sum()方法等于40 -> 当子类没有sum方法,会调用父类的sum()方法等于30
        System.out.println(a.sum1());//会调用子类的sum1()方法等于30->当子类没有sum方法,会调用父类的sum1()方法等于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 getI() {//子类 getI()
        return i;
    }
//    public int sum1() {
//            return i + 10;
//    }
}

 

 六 , 多态的应用

  1)多态数组

    数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

/应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象、2 个 Student  对象和 2 个 Teacher 对象,  统一放在数组
//        中,并调用每个对象
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 + "\t" +age;
    }
}
//-----------------------------------------------------------
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;
    }
    //重写父类的say() 方法
    @Override
    public String say() {
        return "学生" + super.say() + "score" + score;
    }
    //特有方法
    public void study(){
        System.out.println("学生" + getName() + "学习java");
    }
}
//-----------------------------------------------------------
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;
    }
    @Override
    public String say() {
        return "老师 " + super.say() + " salary=" + salary;
    }
    //特有方法
    public void teach() {
        System.out.println("老师 " + getName() + "  正在讲java 课程...");
    }
}
//=======================================
public class PloyArray {
    public static void main(String[] args) {
        Person[] person = new Person[5];
        person[0] = new Person("tom", 25);
        person[1] = new Student("小明" , 16, 100);
        person[2] = new Student("小强" ,18 , 200);
        person[3] = new Teacher("高老师", 32,5000);
        person[4] = new Teacher("赵老师" , 18 , 8000);
        for (int i = 0; i < person.length; i++) { //循环遍历多态数组 调用say方法
            System.out.println(person[i].say());//动态绑定机制  怎么去掉那个子类的特有方法呢 如下
            if (person[i] instanceof Student){
                Student students = (Student)person[i];
                students.study();
            }else if (person[i] instanceof Teacher){
                Teacher teacher = (Teacher)person[i];
                teacher.teach();
            }else {
                System.out.println("你输入的有误");
            }
        }
    }
}

  2)多态参数

    方法定义的形参类型为父类类型,实参类型允许为子类类型

    定义一个员工类Employee,包含姓名和月工资,以及计算年工资getAnnual的方法,普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求重写getAnnual方法

    测试类中添加一个方法showEmpAnnual(Employee e) ,实现获取任何员工对象的年工资,并在main方法中调用该方法e.getAnnual()

    测试类种添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法,

    

public class Employee {  //写一个父类
    private String name;
    private double salary;
    public Employee(String name, double salary) {
        this.name = name;
        this.salary = 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;
    }
    //计算年工资
    public double getAnnual(){
        return salary*12;
    }
}
//----------------------------------------------------
public class Worker extends Employee {  //一个员工类
    public Worker(String name, double salary) {
        super(name, salary);
    }
    public void Work(){
        System.out.println("员工"  + getName() + "努力工作");
    }

    @Override
    public double getAnnual() {
        return super.getAnnual();
    }
}
//------------------------------------------------------------------
public class Manager extends Employee {  经理类
    private double bonus ;
    public Manager(String name, double salary, double bonus) {
        super(name, salary);
        this.bonus = bonus;
    }
    public double getBonus() {
        return bonus;
    }
    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    //管理方法
    public void manage(){
        System.out.println("经理" + getName() + "管理方法");
    }
    @Override
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}
//=================================
public class TestM {
    public static void main(String[] args) {
        Worker tom = new Worker("tom", 5000);
        Manager xiaoming = new Manager("xiaoming", 1000, 5000);
        TestM testM = new TestM();
        testM.showEmpAnnual(tom);
        testM.testWork(tom);
        testM.showEmpAnnual(xiaoming);
        testM.testWork(xiaoming);
    }
    public void showEmpAnnual(Employee employee){
        System.out.println(employee.getAnnual());
    }
    public void testWork(Employee employee){
        if (employee  instanceof Worker){//添加一个方法,testWork,如果是普通员工,
            ((Worker) employee).Work();// 则调用 work 方法,如果是经理,则调用 manage 方法
        }else if (employee instanceof Manager){
            ((Manager) employee).manage();
        }else {
            System.out.println("不做处理");
        }
    }
}

 

总结:多态的概念理解  向上转型  向下转型   多态数组  多态参数     运行看左边  编译看右边   动态绑定机制

 

 

 

 

 

 

 

 



 

posted @ 2022-11-22 15:47  阿文程序猿  阅读(35)  评论(0)    收藏  举报