抽象类 & 接口

如下便是抽象类的一个经典例子:子类(Cat、Dog)继承了父类(Animal),通过重写cry方法实现了不同子类对象的行为特征。

抽象类案例:
系统需求:一加油站推出两种支付卡,一种是预存1W的金卡,后续加油享受8折优惠,另一种是预存0.5W的银卡,后续加油享受8.5折优惠。请分别设计两种卡片进入收银系统后的逻辑,卡片需要包含主人姓名、余额、支付功能。
1、设计金卡银卡的抽象类
1 public abstract class Card {
2 private String username;
3 private double money;
4
5 //提供抽象方法
6 //金卡银卡的具体优惠方式不同
7 public abstract void pay(double money);
8
9 public String getUsername() {
10 return username;
11 }
12
13 public void setUsername(String username) {
14 this.username = username;
15 }
16
17 public double getMoney() {
18 return money;
19 }
20
21 public void setMoney(double money) {
22 this.money = money;
23 }
设计金卡类继承Card类:
1 public class GoldCard extends Card{
2 @Override
3 public void pay(double money) {
4 System.out.println("原价:" + money);
5 //计算优惠后的油价
6 double ret = money * 0.8;
7 double lastMoney = getMoney() - ret;
8 System.out.println("用户:" + getUsername() + "当前实际支付:" + ret + ",剩余:" + lastMoney);
9 //更新卡内余额
10 setMoney(lastMoney);
11 }
12 }
由于银卡的设计方式与金卡的设计方式雷同,再次就先免去了哈~
然后定义一个测试类:
1 public class Test {
2 public static void main(String[] args) {
3 GoldCard goldCard = new GoldCard();
4 goldCard.setUsername("438695");
5 goldCard.setMoney(10000);
6 goldCard.pay(350);
7 System.out.println(gold.Card.getMoney());
8 }
9 }
运行结果:
![]()
问题:抽象类是有构造器的,为什么还抽象类不能被实例化?

思考1:语法上不支持;
思考2:反证法:假设抽象类可以创建对象animal,当animal执行抽象方法的时候又没有具体的方法体,那么该animal便失去了行为执行具体行为的能力,该对象也就失去了意义。
深入思考3: 从上图可以看到,抽象类确实是不能被实例化的,但是它确实是有无参、有参构造器的,我们知道构造器的一个重要作用便是创建对象,无参构造器仅作创建对象的作用,有参构造器是可以在创建对象的同时为对象的属性赋值,既然抽象类都不能创建对象了,那么它还提供构造器作甚?
虽然抽象类的构造器自己是用不到的,但是其子类是可以用的,我们知道:继承抽象类的类便是抽象类的子类,子类在创建对象的时候是先去父类里边调用父类的无参构造器,子类在创建对象的同时还想为对象的属性赋值便可以调用父类的有参构造器,如下:

运行结果:

如此看来,作为一个父类的抽象类,它的构造器更多的就是为了给其子类使用的(虽然它自己不用,也用不了哈~)。
案例:银行利息结算系统
- 某软件公司要为某银行的业务支撑系统开发一个利息结算系统,账户有活期和定期两种,活期是0.35%,定期是1.75%
- 计算利息要先进行用户名、密码验证,验证失败直接提示,登录成功直接进行结算
定义一个抽象类:
1 public abstract class Account {
2 private String username;
3 private double money;
4
5 public Account() {
6 }
7
8 public Account(String username, double money) {
9 this.username = username;
10 this.money = money;
11 }
12
13 //final关键字防止子类重写identify方法导致该模板方法模式失效
14 public final void idenfify(String loginName,String password){
15 if("admin".equals(loginName) && "123456".equals(password)){
16 System.out.println("登录成功");
17 //具体的计算利息交由子类完成
18 double ret = calc(money);
19 System.out.println("用户:"+ username + "利息为:" + ret);
20 }
21 else {
22 System.out.println("登录失败");
23 }
24 }
25 //具体实现在子类内部计算
26 public abstract double calc(double money);
27
28 public String getUsername() {
29 return username;
30 }
31
32 public void setUsername(String username) {
33 this.username = username;
34 }
35
36 public double getMoney() {
37 return money;
38 }
39
40 public void setMoney(double money) {
41 this.money = money;
42 }
43 }
活期账户类:
1 public class CurrentAccount extends Account{
2 @Override
3 public double calc(double money) {
4 return money * 0.075;
5 }
6
7 public CurrentAccount() {
8 }
9
10 public CurrentAccount(String username, double money) {
11 super(username, money);
12 }
13 }
定期账户类:
1 public class FixedAccount extends Account{
2 @Override
3 public double calc(double money) {
4 return money * 0.035;
5 }
6
7 public FixedAccount() {
8 }
9
10 public FixedAccount(String username, double money) {
11 super(username, money);
12 }
13 }
测试类:
1 public class Test {
2 public static void main(String[] args) {
3 CurrentAccount currentAccount = new CurrentAccount("CA01",50000);
4 currentAccount.idenfify("admin","123456");
5 System.out.println("-------------");
6 FixedAccount fixedAccount = new FixedAccount("FA01",120000);
7 fixedAccount.idenfify("admin","123456");
8 }
9 }
运行实例:

接口:

示例运行结果:

接口的规范化合并:

从上边两个例子可以看出,接口是支持多继承的
接口新增方法:
1、默认方法(默认用public修饰,必须用default修饰),类似于实例方法,但由于接口是不能创建对象的,该方法相当于过继给了子类使用

2、静态方法:必须用static修饰,默认用public修饰,只能由接口名.静态方法名调用,与之前不同的是接口内的静态方法不能用子类名.静态方法名调用。

3、私有方法,只在本类中调用
扩充:IDEA如何更改JDK版本



浙公网安备 33010602011771号