java中多态的理解

多态是继封装、继承之后,面向对象的第三大特性。

生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

定义
  • 多态: 是指同一行为,对于不同的对象具有多个不同表现形式。
  • 程序中多态: 是指同一方法,对于不同的对象具有不同的实现.
前提条件【重点】
  1. 继承或者实现【二选一】
  2. 父类引用指向子类对象【格式体现】
  3. 方法的重写【意义体现:不重写,无意义】

小结:

  • 多态: 是指同一行为,对于不同的对象具有多个不同表现形式。
  • 条件:
    • 继承或者实现
    • 父类引用指向子类的对象
    • 方法的重写

知识点-- 实现多态

目标:

  • 如何实现多态

路径:

  • 多态的实现

讲解:

多态的体现:父类的引用指向它的子类的对象

父类类型 变量名 = new 子类对象;
变量名.方法名();

父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

  • 多态实现方式一:通过继承类
abstract class Animal{
    public abstract void eat();
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头...");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼...");
    }
}
public class Test1 {
    public static void main(String[] args) {
        // 父类的引用指向子类的对象
        Animal anl = new Dog();
        anl.eat();// 狗吃骨头...

        anl = new Cat();
        anl.eat();// 猫吃鱼...


    }
}
  • 多态实现方式二:通过实现接口
interface A{
    void method();
}
class Imp implements A{

    @Override
    public void method() {
        System.out.println("重写method");
    }
}
public class Test2 {
    public static void main(String[] args) {
        // 父接口的引用指向实现类的对象
        A a = new Imp();
        a.method();
    }
}

小结:

  • 继承或者实现
  • 父类的引用指向子类的对象
  • 方法的重写

知识点-- 多态时访问成员的特点

目标

  • 掌握多态时访问成员的特点

路径:

  • 多态时成员变量的访问特点
  • 多态时成员方法的访问特点

讲解:

  • 多态时成员变量的访问特点
    • 编译看左边,运行看左边
      • 简而言之:多态的情况下,访问的是父类的成员变量
  • 多态时成员方法的访问特点
    • 非静态方法:编译看左边,运行看右边
      • 简而言之:编译的时候去父类中查找方法,运行的时候去子类中查找方法来执行
    • 静态方法:编译看左边,运行看左边
      • 简而言之:编译的时候去父类中查找方法,运行的时候去父类中查找方法来执行
  • 注意:多态的情况下是无法访问子类独有的方法
  • 演示代码:
class Fu{
    int num = 10;
    // 非静态方法
    public void method1(){
        System.out.println("Fu 非静态方法method1");
    }
    // 静态方法
    public static void method2(){
        System.out.println("Fu 静态方法method2");
    }
}
class Zi extends Fu{
    int num = 20;
    // 非静态方法
    @Override
    public void method1(){
        System.out.println("Zi 非静态方法method1");
    }
    // 静态方法
    public static void method2(){
        System.out.println("Zi 静态方法method2");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            多态时访问成员的特点:
                成员变量:编译看父类,运行看父类(编译看左边,运行看左边)
                成员方法:
                    非静态方法: 编译看父类,运行看子类(编译看左边,运行看右边)
                    静态方法:   编译看父类,运行看父类(编译看左边,运行看左边)
                记忆:
                    除了非静态方法,编译看父类,运行看子类,其余都是看父类
         */
        // 父类的引用指向子类的对象
        Fu f = new Zi();
        System.out.println(f.num);// 10
        f.method1();
        f.method2();
    }
}

小结:

  • 除了非静态方法,编译看父类,运行看子类,其余都是看父类

知识点-- 多态的几种表现形式

目标:

  • 多态的几种表现形式

路径:

  • 普通父类多态
  • 抽象父类多态
  • 父接口多态

讲解:

  • 多态的表现形式:

    • 普通父类多态
class Fu{}
class Zi extends Fu{}
public class Test {
    public static void main(String[] args) {
        Fu f = new Zi();
    }
}
  • 抽象父类多态
abstract class Fu{}
class Zi extends Fu{}
public class Test {
    public static void main(String[] args) {
        Fu f = new Zi();
    }
}
  • 父接口多态
interface A{}
class Imp implements A{}
public class Test {
    public static void main(String[] args) {
        A a = new Imp();
    }
}

知识点-- 多态的应用场景:

目标:

  • 掌握多态在开发中的应用场景

路径:

  • 变量多态 -----> 意义不大
  • 形参多态----> 常用
  • 返回值多态—> 常用

讲解:

多态的几种应用场景:

  • 变量多态
class Fu{}
class Zi extends Fu{}

public class Test {
    public static void main(String[] args) {
        // 变量多态---一般不使用,意义不大,除非用来检验调用父类的方法
        Fu f = new Zi();
    }
}
  • 形参多态

  • 参数的类型为父类类型,就可以传入该父类类型的对象,或者该父类类型的所有子类对象

abstract class Animal{
    public abstract void eat();
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
//.... 很多的子类.....

public class Test {
    public static void main(String[] args) {
        // 形参多态---- 必须掌握
        Dog d = new Dog();
        method(d);

        System.out.println("==============================");
        Cat c = new Cat();
        method(c);
    }
    // 定义一个方法,既可以接收Dog类的对象,又可以接收Cat类的对象(也就是说要能接收Animal类的所有对象)
    // 结论: 参数的类型为父类类型,就可以传入该父类类型的对象,或者该父类类型的所有子类对象
    public static void method(Animal anl){
        anl.eat();
    }

   /* public static void method(Dog d){
        d.eat();
    }
    public static void method(Cat c){
        c.eat();
    }*/
    //....
}
  • 返回值多态

  • 如果方法的返回值类型为父类类型,那么就可以返回该父类对象,或者该父类的所有子类对象

abstract class Animal{
    public abstract void eat();
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class Test {
    public static void main(String[] args) {
        Animal anl1 = method(1);// 返回狗类对象
        Animal anl2 = method(3);// 返回猫类对象
    }

    // 结论:如果方法的返回值类型为父类类型,那么就可以返回该父类对象,或者该父类的所有子类对象
    public static Animal method(int num){
        if (num == 3){
            // 返回猫
            Cat c = new Cat();
            return c;
        }else {
            // 返回狗
            Dog d = new Dog();
            return d;
        }
    }
}

小结:

  • 如果参数的类型为父类类型,name就可以传入该父类类型的对象,或者该父类类型的所有子类对象
  • 如果方法的返回值类型为父类类型,那么就可以返回该父类类型的对象,或者该父类的所有子类对象

知识点-- 多态的好处和弊端

目标:

  • 实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。但有好处也有弊端

步骤:

  • 多态的好处和弊端

讲解:

  • 好处
    • 提高了代码的扩展性
  • 弊端
    • 多态的情况下,只能调用父类的共性内容,不能调用子类的特有内容。
  • 示例代码
// 父类
public abstract class Animal {  
    public abstract void eat();  
}  
// 子类
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void catchMouse(){
         System.out.println("猫抓老鼠");  
    }
}  
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
}

定义测试类:

abstract class Animal{
    public abstract void eat();
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void lookHome(){
        System.out.println("狗看家...");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠...");
    }
}
public class Test1 {
    public static void main(String[] args) {
        /*
            - 好处
              - 提高了代码的扩展性
            - 弊端
              - 多态的情况下,只能调用父类的共性内容,不能调用子类的特有内容。
         */
        Dog d = new Dog();
        method(d);

        System.out.println("=========================");

        Cat c = new Cat();
        method(c);
    }

    public static void method(Animal anl){
        anl.eat();
        //anl.lookHome();// 编译报错,因为多态的成员访问特点:编译看父类,父类中没有,就报错
        //anl.catchMouse();// 编译报错,因为多态的成员访问特点:编译看父类,父类中没有,就报错

    }
}

知识点-- 引用类型转换

目标:

  • 向上转型与向下转型,instanceof关键字

步骤:

  • 向上转型
  • 向下转型
  • instanceof关键字

讲解:

向上转型
  • 子类类型向父类类型向上转换的过程,这个过程是默认的。
 Aniaml anl = new Cat();  
向下转型
  • 父类类型向子类类型向下转换的过程,这个过程是强制的。
 Aniaml anl = new Cat();  
 Cat c = (Cat)anl;//向下转型
 c.catchMouse();// 可以访问 子类独有的功能,解决多态的弊端
instanceof关键字
  • 向下强转有风险,最好在转换前做一个验证 :

  • 格式:

变量名 instanceof 数据类型 
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false。

if( anl instanceof Cat){//判断anl是否能转换为Cat类型,如果可以返回:true,否则返回:false
    Cat c = (Cat)anl;//安全转换
}
class Animal{
    public  void eat(){}
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    // 看家
    public void lookHome(){
        System.out.println("狗看家...");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    // 抓老鼠
    public void catchMouse(){
        System.out.println("猫抓老鼠...");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            引用类型转换:
                向上转型: 子类类型向父类类型向上转换的过程,这个过程是默认的。
                向下转型: 父类类型向子类类型向下转换的过程,这个过程是强制的。
                         格式: 子类类型 变量名 = (子类类型)父类类型的变量;
                         注意: 右边只能是父类类型的变量,并且该变量指向的是要转换的子类类型的对象

                规范: 为了保证转型不出问题,一般转型之前需要进行类型判断----instanceof关键字
                    格式:
                        if(变量名 instanceof 数据类型){

                        }
                    如果变量指向的对象是属于后面的数据类型,返回true。
                    如果变量指向的对象不属于后面的数据类型,返回false。

         */
        // 向上转型
        Animal anl = new Dog();

        // 向下转型
        //Animal a = new Animal();
        //Dog d = (Dog)a;// 运行报错 ClassCastException类型转换异常

        //Dog d = (Dog)anl;// 没有问题
        //Cat c = (Cat)anl;// 运行报错 ClassCastException类型转换异常

        System.out.println("============================================");
        if (anl instanceof Dog){
            Dog d = (Dog)anl;
            d.eat();
            d.lookHome();
        }
    }
}

解决多态的弊端

abstract class Animal{
    public abstract void eat();
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void lookHome(){
        System.out.println("狗看家...");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠...");
    }
}

public class Test1 {
    public static void main(String[] args) {
        /*
            - 好处
              - 提高了代码的扩展性
            - 弊端
              - 多态的情况下,只能调用父类的共性内容,不能调用子类的特有内容。
         */
        Dog d = new Dog();
        method(d);

        System.out.println("=========================");

        Cat c = new Cat();
        method(c);
    }

    public static void method(Animal anl){
        anl.eat();
        // 判断anl指向的是否是Dog对象
        if (anl instanceof Dog){
            Dog d = (Dog)anl;
            d.lookHome();
        }
        // 判断anl指向的是否是Cat对象
        if (anl instanceof Cat){
            Cat c = (Cat)anl;
            c.catchMouse();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值