java
Payable[] methods = {
new Alipay(1000),
new WechatPay(500),
new CreditCard(2000)
};
学习java的时候,发现一段好玩的代码。
这个和平时写的Payable p = new Alipay(),有所不同。
需要拆成三步理解:
声明一个数组:Payable\[\] methods
数组类型是 Payable(接口类型)
意思是:这个数组里装的元素,必须是"实现了 Payable 接口的对象"
创建三个对象:
new Alipay(1000) → 支付宝对象,余额 1000
new WechatPay(500) → 微信对象,余额 500
new CreditCard(2000) → 信用卡对象,额度 2000
放进数组:
这三个对象的实际类型分别是 Alipay、WechatPay、CreditCard
但它们的引用类型都被当作 Payable
这里需要说到一个引用类型和实际类型区别
java
Payable p = new Alipay(1000);
// ↑ ↑
// 引用类型 实际类型
// (接口) (具体类)
引用类型(编译时) Payable 编译器只认它是 Payable,只能调用 Payable 里声明的方法
实际类型(运行时) Alipay JVM 知道它真正是 Alipay,调用方法时执行 Alipay 的实现
这就是向上转型(upcasting):子类对象可以自动赋值给父类/接口引用,因为"支付宝 是一种 支付方式"。
为什么能这样写呢?
因为 Alipay、WechatPay、CreditCard 都 implements Payable:
java
public class Alipay implements Payable { ... }
public class WechatPay implements Payable { ... }
public class CreditCard implements Payable { ... }
所以它们都满足"是一个 Payable"的条件,可以放进 Payable\[\] 数组。
以及后面的这一段代码
java
for (Payable p : methods) {
System.out.println("当前余额/额度:" + p.getBalance());
p.pay(300);
System.out.println("---");
}
我觉得这一段代码的for有点类似JavaScript中的for in与for of的写法,像一种简写。
变量 p 的引用类型永远是 Payable
但每次循环,p 指向的实际对象不同
调用 p.pay(300) 时,JVM 在运行时根据实际类型决定执行哪个 pay()。
java
循环轮次 p实际指向 执行的方法
第 1 轮 Alipay 对象 Alipay.pay()
第 2 轮 WechatPay 对象 WechatPay.pay()
第 3 轮 CreditCard 对象 CreditCard.pay()
同一行代码 p.pay(300),运行时表现不同 ------ 这就是多态(动态绑定 / 运行时绑定)。