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!