zoukankan      html  css  js  c++  java
  • Java基础之:OOP——多态

    Java基础之:OOP——多态

    多态(polymorphic)即多种形态,是程序基于封装和继承之后的另外一种应用。

    首先我们先看一个案例,了解为什么要使用多态。

    实现一个应用 : 1.小范既是儿子 也是 父亲 (多种形态),2.儿子用钱买糖 , 父亲卖报纸给商家赚钱

    package polymorphic_ClassTest;
    ​
    public class PolyTest {
    ​
        public static void main(String[] args) {
            Father father = new Father("父亲(小范)",40);
            Son son = new Son("儿子(小范)",20);
            Candy candy = new Candy("买糖果");
            Newspaper newspaper = new Newspaper("卖报纸");
            
            tarding(son,candy); //儿子买糖果
            tarding(father,newspaper);  //父亲卖报纸
            
            //通过多态引入,我们也可以体现    儿子卖报纸 , 父亲买糖果
            tarding(father,candy);
            tarding(son, newspaper);
            
        }
        
        
        //试想如果   父亲也要买糖果,那么就又需要重写一个tarding方法.....
        //会有很多的组合方式,为了不重写tarding方法。引入多态的概念
        //使用以前的封装+继承方法实现:
        public static void tarding(Son son,Candy candy) {
            
            System.out.println(son.getName() + "买" + candy.getName());
        }
        
        public static void tarding(Father father,Newspaper newspaper) {
            
            System.out.println(father.getName() + "卖" + newspaper.getName());
        }
        
        //使用多态来实现:
        public static void tarding(Person person,Goods goods) {
            //实现原理:   Son和Father继承于Person类,Candy和Newspaper继承于Goods类
            System.out.println(person.getName() + "  交易    " + goods.getName());
        }
    ​
    }
    ​
    class Person{
        
        private String name;
    ​
        public Person(String name) {
            super();
            this.name = name;
        }
    ​
        public Person() {
            super();
        }
    ​
        public String getName() {
            return name;
        }
    ​
        public void setName(String name) {
            this.name = name;
        }
    ​
    }
    ​
    class Son extends Person{
        private int age;
        
        public Son(String name, int age) {
            super(name);
            this.age = age;
        }
    }
    ​
    class Father extends Person{
        
        private int age;
        
        public Father(String name, int age) {
            super(name);
            this.age = age;
        }
    }
    ​
    class Goods{    //商品
        
        private String name;
    ​
        public Goods(String name) {
            super();
            this.name = name;
        }
    ​
        public Goods() {
            super();
        }
    ​
        public String getName() {
            return name;
        }
    ​
        public void setName(String name) {
            this.name = name;
        }
        
    }
    ​
    class Candy extends Goods{
        public Candy(String name) {
            super(name);
        }
    }
    ​
    class Newspaper extends Goods{
        public Newspaper(String name) {
            super(name);
        }
    }

    运行结果

     

    多态的具体体现

    重写与重载

    public class PolyOverLoad {
    ​
        public static void main(String[] args) {
            
            //方法重载体现多态
            T t = new T();
            t.say(100);
            t.say("tom");
        }
    ​
    }
    ​
    class T {
        public void say(String name) {
            System.out.println("hi " + name);
        }
        public void say(int num) {
            System.out.println("hello" + num);
        }
    }
    ​
    //=======================================================
    ​
    public class PolyOverride {
    ​
        public static void main(String[] args) {
    ​
            AA a = new AA();
            a.hi("jack");
            
            BB b = new BB();
            b.hi("tom");
        }
    ​
    }
    ​
    class AA {
        public void hi(String name) {
            System.out.println("AA " + name);
        }
    }
    ​
    class BB extends AA {
        @Override
        public void hi(String name) { //子类hi 重写 父类的 hi
            System.out.println("BB " + name);
        }
    }

     

    对象的多态(编译类型与运行类型)

    package polymorphic;
    ​
    public class PolyTest {
    ​
        public static void main(String[] args) {
            /*
             *  语法:父类名   对象 = new 子类构造器;(父类引用指向子类对象)
             *  此时animal实际存在两种类型:1.编译类型 ;2.运行类型
             *   编译类型:编译器识别时的类型,即等号左边的类型。这里animal的编译类型就是Animal
             *          在程序员编译时,只能访问编译类型有的 方法和属性 
             *          对于对象的编译类型而言,是不变的。
             *  运行类型:JVM运行时的类型,即等号右边的类型。这里animal的运行类型就是Dog
             *          对于对象的运行类型而言,是可变的。
             */
            
            
            //向上转型  语法:父类类型  父类对象 = new  子类类型();
            Animal animal = new Dog();
            animal.eat();
    //      animal.run(); //报错 :The method run() is undefined for the type Animal 
            
            animal = new Cat();//改变了animal的运行类型,但编译类型不变
            animal.eat();
            animal.show(); //1.首先寻找在Cat中的show  2.若没有则向上寻找父类Animal的show
            
            //向下转型 语法: 子类类型  子类对象 = (子类类型)父类对象
            Cat cat = (Cat)animal;//这里是创建了一个Cat引用,让cat 指向  animal指向的那个堆地址空间
    //      Dog dog = (dog)animal;//要想这样向下强行转换类型,必须满足 animal堆空间中的类型就是cat
            cat.drink();
            
        }
    ​
    }
    ​
    class Animal{
        public void eat() {
            
            System.out.println("eat......");
        }
        
        public void show() {
            System.out.println("show..........");
        }
        
    }
    ​
    class Dog extends Animal{
        @Override
        public void eat() {
            System.out.println("Dog  eat......");
        }
        public void run() {
            
            System.out.println("run........");
        }
    }
    ​
    class Cat extends Animal{
        @Override
        public void eat() {
            System.out.println("Cat  eat......");
        }
        public void drink() {
            
            System.out.println("drink........");
        }
        
    //  public void show() {
    //      System.out.println("Cat  show..........");
    //  }
    }

     

    结合实际案例理解编译类型与运行类型

    •   对于编译类型和运行类型,通过这样一个现实的例子来理解。
    •   大家都知道披着羊皮的狼,那可能也会有披着羊皮的人。
    •   那么这里的羊皮就是编译类型,羊皮是始终不变的,不管是谁披上它,它都是羊皮。
    •   而我们可以把编译器看成一个很"肤浅"的家伙,它只会看到表面的东西,所以如果在编译类型中没有的方法,不可以通过对象进行调用(即使在运行类型中确实存在此方法)。
    •   这里的狼和人就是运行类型,运行类型是可变的。(羊皮可能被任何东西给披上)
    •   相对于编译器而言JVM就显得有"内涵"一些了,运行类型就是在JVM运行程序时,对象实际的类型,所以运行类型可以调用在运行类型中有的方法。
    •   就好比,披着羊皮的狼,你以为它是吃草的,编译器也认为它是吃草的。但它实际上是吃肉的,JVM在运行时也认为它是吃肉的。

     

    案例说明(向上转型与向下转型)

    向上转型 语法:父类类型 父类对象 = new 子类类型();

      对于向上转型而言,就是将父类引用指向子类对象。

      向上转型可以通过改变运行类型的方式,通过一个父类引用访问多个子类对象。

        例如:

          Animal animal = new Dog();

          animal = new Cat();

    向下转型 语法: 子类类型 子类对象 = (子类类型)父类对象;

      对于向下转型而言,就是将父类对象强制转换为子类对象。

      所以要做到向下转型,前提条件就是父类对象原本的运行类型就是子类类型。

        例如:

          Animal animal = new Dog();

          Dog dog = (dog)animal;

      但要注意的是,向下转型是将一个子类引用Dog指向了原来在堆空间创建的那个Dog对象。

      而animal同样指向堆空间中的Dog对象,所以向下转型之后 animal (父类引用)本身不受影响。

     

    属性多态

    对于类型的属性而言,没有编译类型与运行类型的说法。

    即属性只认编译类型,通过多态声明后,访问属性时,也只会返回编译类型中的属性对应的值。

    public class PolyProperties {
    ​
        public static void main(String[] args) {
            Base base = new Base();
            System.out.println(base.n); // 200
            
            Base base2 = new Sub();
            System.out.println(base2.n); // 属性没有重写之说!属性的值看编译类型
        }
    }
    ​
    class Base {
        public int n = 200;
    }
    ​
    class Sub extends Base {
        public int n = 300;
    }

     

    instanceOf关键字

    instanceOf关键字用于比较 对象的类型 是否是指定类型或其子类

    public class InstanceOfTest {
        public static void main(String[] args) {
        
            AA bb = new BB();
            //instanceOf 比较操作符,用于判断某个对象的运行类型是否为XX类型或XX类型的子类型
            System.out.println(bb instanceof BB); // T
            System.out.println(bb instanceof AA); // T
            System.out.println(bb instanceof Object); // T
            Object obj = new Object();
            System.out.println(obj instanceof AA);// F  
        }
    }
    ​
    ​
    class AA{
        
        
    }
    ​
    class BB extends AA{
        
        
    }
    

     

    Java的动态绑定机制

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

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

    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;
       // }
    }
    ​
    public class Test{
        public static void main(String args[]){
            A a = new B();                //不注销       注销
            System.out.println(a.sum());  //40    =》    30
            System.out.println(a.sum1()); //30    =》    20
            //这里要注意,getI()方法是动态绑定在B对象上的,所以在调用A类的sum()方法时,getI()仍然会返回B类中的I的值。
        }
    }

     

    多态应用案例

    应用实例:现有一个继承结构如下:要求创建五个年龄不等的Person1、Student [2]和Teacher[2]对象。

    调用子类特有的方法,比如Teacher 有一个 teach , Student 有一个 study怎么调用

    提示 : [实现在多态数组调用各个对象的方法]遍历+instanceof + 向下转型

    package polymorphic_PolyArrays;
    
    public class PolyArrays {
    ​
        public static void main(String[] args) {
    ​
            Person[] persons = {new Person("jack", 10), new Student("tom",20, 78), new Student("king",21, 68)
                    , new Teacher("老王", 50, 10000), new Teacher("老李", 45, 20000)};
            
            Traverse(persons);
        }
        
        public static void Traverse(Person[] person) {
            for (int i = 0; i < person.length; i++) {
                if(person[i] instanceof Student) {
    //              ((Student)person[i]).study();   //这种方式更好
                    Student stu = (Student)person[i];
                    stu.study();
                }else if(person[i] instanceof Teacher) {
    //              ((Teacher)person[i]).teach();   //这种方式更好
                    Teacher tea = (Teacher)person[i];
                    tea.teach();
                }else {
                    System.out.println(person[i].say());
                }
            }
        }
    }
    ​
    class Person  {
        
        private String name;
        private int age;
        public Person(String name, int age) {
            super();
            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;
        }
    }
    ​
    class Student extends Person {
        private double score;
    ​
        public double getScore() {
            return score;
        }
    ​
        public void setScore(double score) {
            this.score = score;
        }
    ​
        public Student(String name, int age, double score) {
            super(name, age);
            this.score = score;
        }
        
        public void study() {
            System.out.println("学生 " + getName() + " is studying java...");
        }
        
    }
    ​
    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 void teach() {
            System.out.println("老师 " + getName() + " is teaching java ");
        }
        
    }

     

  • 相关阅读:
    javascript线性渐变2
    javascript无缝滚动2
    javascript Object对象
    javascript无缝滚动
    javascript图片轮换2
    javascript图片轮换
    用C/C++写CGI程序
    linux shell 的 for 循环
    重磅分享:微软等数据结构+算法面试100题全部答案完整亮相
    查看linux服务器硬盘IO读写负载
  • 原文地址:https://www.cnblogs.com/SongHai/p/14110235.html
Copyright © 2011-2022 走看看