Java面向对象-多态详解

1.通过现象认识多态

1.1 编码背景

1.定义一个用户类 User,拥有属性 loginName 和 nickName ,登录名和昵称,拥有方法 login();
2.定义一个管理者用户类 UserManager,独有属性 level,表示管理等级,继承 用户类 User,并重写方法 login();
3.定义一个普通用户类 UserOrdinary,独有属性registedDate,表示注册时间,继承 用户类 User,并重写方法 login();
4.定义一个测试类 Application,声明一个静态方法userLogin(User user)进行测试。

UML图如下所示: 

在这里插入图片描述

1.2 java代码

User类

public class User {
    // 两个属性 : 用户都有 登录名 和 昵称
    protected  String loginName;
    protected String nickName;

    // 一个方法 : 登录
    protected void login(){
        System.out.println("=== User login ===");
    }

    // 对应属性的getter/setter 方法
    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
}

UserManager类

public class UserManager extends User {

    // 有自己独有的属性 level 表示管理者的级别
    private Integer level;

    // 对应属性的getter/setter 方法
    public Integer getLevel() {
        return level;
    }

    public void setLevel(Integer level) {
        this.level = level;
    }

    // 重写父类的login方法
    @Override
    protected void login() {
        System.out.println("=== UserManager Login begin ===");
        System.out.println("== UserManager say hello to you ==");
        System.out.println("=== UserManager Login end ===");
    }
}

UserOrdinary类

public class UserOrdinary extends User {

    // 普通用户独有的属性 : 注册时间
    private Date registedDate;

    // 对应的getter/setter方法
    public Date getRegistedDate() {
        return registedDate;
    }

    public void setRegistedDate(Date registedDate) {
        this.registedDate = registedDate;
    }
    // 重写父类的方法
    @Override
    protected void login() {
        System.out.println("=== UserOrdinary Login begin ===");
        System.out.println("== UserOrdinary say hello to you ==");
        System.out.println("=== UserOrdinary Login end ===");
    }
}

Application类 : 测试用

public class Application {

    /**
     * 声明一个方法,参数为 User 的对象,然后调用 user的login()方法
     * @param user
     */
    public static void userLogin(User user){
        user.login();
    }

    public static void main(String[] args) {
        // 1. 创建一个User对象
        User user = new User();
        userLogin(user);
        System.out.println("***********************************");
        // 2. 创建一个UserManager对象
        UserManager userManager = new UserManager();
        userLogin(userManager);
        System.out.println("***********************************");
        // 3. 创建一个UserOrdinary对象
        UserOrdinary userOrdinary = new UserOrdinary();
        userLogin(userOrdinary);
        System.out.println("***********************************");
    }
}

运行结果

=== User login ===
***********************************
=== UserManager Login begin ===
== UserManager say hello to you ==
=== UserManager Login end ===
***********************************
=== UserOrdinary Login begin ===
== UserOrdinary say hello to you ==
=== UserOrdinary Login end ===
***********************************

1.3 现象分析

Application.userLogin(User user) 方法分析

1.方法参数为 User 类型的对象;
2.方法体 调用了 user对象的login()方法;

Application.main()方法内容分析

1. 创建一个User对象user作为方法useLogin()的参数,执行结果为 User类中的login()的打印内容;
2. 创建一个UserManager对象作为方法useLogin()的参数,执行结果为 UserManager类中的login()的打印内容;
3. 创建一个UserOrdinary对象作为方法useLogin()的参数,执行结果为 UserOrdinary类中的login()的打印内容;

2.通过原理理解多态

2.1 向上转型

提出问题 : 为什么userLogin()的方法参数是 User类型,而实际调用过程中传入 子类的对象也可以?

答 : 1. “子类 是 父类” ==》 is a 的理解。
      2. is a : “管理员用户” 和 “普通用户” 都是 “用户”! 就像 “男老师和女老师都是老师”一个道理。
      3. 因此, 可以把子类对象作为方法的参数,而这种现象就叫做 向上转型。

类型判断 : instanceof

		// 声明两个对象 : 一个多态、一个正常
 	  User user3 = new UserOrdinary();
      UserOrdinary user4 = new UserOrdinary();

		// 使用 instanceof 来判断是否时对应的对象
        if (user3 instanceof User){
            System.out.println("user3 is a User");
        }else{
            System.out.println("user3 is not a User");
        }
        if (user4 instanceof User){
            System.out.println("user4 is a User");
        }else{
            System.out.println("user4 is not a User");
        }

执行结果:
user3 is a User
user4 is a User

2.2 动态绑定

提出问题 : 为什么实际执行的过程中会调用不同的方法呢?

答 : 原因就是动态绑定!
   动态绑定是在运行时发生的,会找到父类引用所指向的子类对象的真正类型,进而调用对应的方法。
   例如 : 参数为 userManager对象时,
          在程序的编译过程中, 通过 向上转型  认为子类对象也是父类对象,编译可以通过;
          在执行过程中,会以真正的子类对象中的login()方法进行执行。
          【即 编译看左边,执行看右边】

2.3 简化版的 多态的例子

 		/**
         * 1.正常的创建对象和调用方法
         */
        User user = new User();
        UserManager userManager = new UserManager();
        UserOrdinary userOrdinary = new UserOrdinary();
        user.login();
        userManager.login();
        userOrdinary.login();
        System.out.println("********************");
        /**
         * 2.多态形式的创建对象和调用方法
         */
        User user2 = new UserManager();
        User user3 = new UserOrdinary();
        user2.login();
        user3.login();

3.多态小结

1.存在继承关系;
2.子类重写父类的方法;
3.父类引用指向子类对象;
4.调用父类的方法,根据父类引用变量指向的子类对象找到真正的子类方法进行执行。
5.多态是方法的多态,与属性无关。

4.完成

Congratulations!
You are one step closer to success!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值