Java面向对象特征3之多态性

1 - 什么是多态

/*
也叫对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

Person[父类] p1 = new Man()[子类];

Person p1 = new Man();
*/

 

2 - 理解多态性

/*
理解多态性:可以理解为一个事务的多种形态。
*/

3 - 多态性使用

/*

1-前提:

  ①首先要有类的继承关系

  ②要有方法的重写

2-多态性的使用:虚拟方法调用

  有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写的方法
  总结:编译,看左边,运行看右边 Person[左边] p1 = new Man()[右边];

3-对象的多态性:只适用于方法,不适用于属性

*/

代码示例

package com.lzh.exer1;

import java.sql.Connection;

/*
 * 多态性的使用举例1
 */
public class AnimalTest {
    public static void main(String[] args) {
        AnimalTest animal = new AnimalTest();
        
        animal.func(new Dog());
        animal.func(new Cut());
    }
    
    public void func(Animal animal) { // Animal animal = new Dog(); 多态性的体现
        animal.eat();
        animal.shout();
    }
    // 如果没有多态性,省略重载方法
//    public void func(Dog dog) {
//        dog.eat();
//        dog.shout();
//    }
//    public void func(Cut cut) {
//        cut.eat();
//        cut.shout();
//    }
}

class Animal{
    public void eat() {
        System.out.println("动物:进食");
    }
    public void shout() {
        System.out.println("动物:叫");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        // super.eat();
        System.out.println("吃狗粮");
    }
    @Override
    public void shout() {
        // TODO Auto-generated method stub
        // super.shout();
        System.out.println("汪汪");
    }
}

class Cut extends Animal{
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        // super.eat();
        System.out.println("猫吃鱼");
    }
    @Override
    public void shout() {
        // TODO Auto-generated method stub
        // super.shout();
        System.out.println("喵喵");
    }
}
/*
 * 多态性的使用举例2
 */
class Order{
    public void method(Object object) {
        // object.xxx
    }
}
/*
 * 多态性的使用举例3
 */
class Driver{
    public void doData(Connection conn) { // conn = new MySQLConnection();
        // 规范的操作数据
        //conn.method1();
        //conn.method2();
        //conn.method3();
    }
}
多态性的使用举例

4 - 虚拟方法调用

 * 

5 - 小结:方法的重载与与重写

 

6 - 面试题:多态是编译时行为还是运行时行为?

import java.util.Random;

//面试题:多态是编译时行为还是运行时行为?
//证明如下:
class Animal  {
 
    protected void eat() {
        System.out.println("animal eat food");
    }
}

class Cat  extends Animal  {
 
    protected void eat() {
        System.out.println("cat eat fish");
    }
}

class Dog  extends Animal  {
 
    public void eat() {
        System.out.println("Dog eat bone");

    }
}

class Sheep  extends Animal  {
 

    public void eat() {
        System.out.println("Sheep eat grass");

    }
}

public class InterviewTest {

    public static Animal  getInstance(int key) {
        switch (key) {
        case 0:
            return new Cat ();
        case 1:
            return new Dog ();
        default:
            return new Sheep ();
        }
    }

    public static void main(String[] args) {
        int key = new Random().nextInt(3);

        System.out.println(key);

        Animal  animal = getInstance(key);
        
        animal.eat();
    }
}
证明

/*
结论:多态是运行行为
*/

7 - instanceof 操作符 


使用情景:为了避免在向下转型是出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型

8 - 对象类型转换

/*
Person p1 = new Man(); // Person为父类,Man为Person的子类

// p1.earMoney(); Man所特有的方法

// p1.isSmoking = true; Man所特有的属性

①此时p1不能调用子类(Man())所特有的方法、属性:编译时,p1是Person类型

②有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

③如何才能调用子类特有的属性和方法? 使用强制类型转换符

  Man m1 = (Man)p1;

  m1.earMoney(); // 这时就可以调用Man类所特有的方法和属性

  m1.isSmoking();

  // 使用强转时,可能出现ClassCastException的异常

④instanceof 关键字的使用

  a instanceof A :判断对象a是否是类A的实例。如果是,返回true,如果不是,返回false

  if(p1 instanceof Man){

    Man m1 = (Man)p1;

    ...

  }
*/

9 - 继承成员变量和继承方法的区别

package com.lzh.exer1;
/*
 * 说明:
 *     1-若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
 * 
 *     2-对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的相同实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
 */
class Base {
    int count = 10;
    public void display() {
        System.out.println(this.count);
    }
}

class Sub extends Base {
    int count = 20;

    public void display() {
        System.out.println(this.count);
    }
}

public class FieldMethodTest {
    public static void main(String[] args) {
        Sub s = new Sub();
        
        System.out.println(s.count); // 20
        s.display(); // 20
        
        Base b = s; // 多态性
        
        System.out.println(b == s); // true
        System.out.println(b.count); // 10
        b.display(); // 20
    }
}
练习

/*
说明:

1-若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边

2-对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的相同实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边

*/

posted @ 2020-06-02 22:26  赖正华  阅读(151)  评论(0编辑  收藏  举报