抽象类的定义
- 在Java中abstract是定义抽象类的 可以修饰类 成员方法
- abstract修饰类 这个类就是抽象类;
- abstract修饰方法 这个方法就是抽象方法
修饰符 abstract class 类名{
修饰符 abstract 返回值类型 方法名称(形参列表);
}
//如:
public abstract class Dog{
public abstract void run();//抽象方法只有方法签名,不能声明方法体。
}
注意:一个类中如果定义了抽象方法 这个类必须声明成抽象类 否则报错
抽象类的基本使用
- 抽象类可以理解成不完整的设计图 一般作为父类 让子类来继承
- 当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同,于是该父类就把该行为定义成抽象方法的形式,具体实现交给子类去完成。此时这个类就可以声明成抽象类。
//父类
public abstract class Test_1 {
private String name;
public abstract void run();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//子类
public class Dog extends Test_1{
@Override
public void run() {
System.out.println("狗跑得快");
}
}
//就近原则用子类重写的方法
public class Tool_ {
public static void main(String[] args) {
Dog d = new Dog();
d.run();
}
}
抽象类的案例
需求:
某加油站推出了支付卡,预存10000的金卡,后续加油享受8折优惠。
请分别实现卡片进入收银系统后的逻辑,卡片需要包含主人名称,余额,支付功能。
思路:
创建一张卡片父类:定义属性包括主人名称、余额、支付功能(具体实现交给子类)
//父类
public abstract class Card {
private String user_name;
private double money;
//定义一个抽象支付方法
public abstract void pay(double money2);
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
创建一张白金卡类:重写支付功能,按照原价的8折计算输出。
//子类 金卡类
public class Gold_card extends Card{
@Override
public void pay(double money2) {
System.out.println("当前消费:"+money2);
System.out.println("当前卡片余额为:"+getMoney());
//进行优惠价计算
double s = money2 * 0.8;
System.out.println("实际支付"+s);
//更新账余额
setMoney(getMoney() - s);
}
}
测试
//测试类
public class Test {
public static void main(String[] args) {
Gold_card gc = new Gold_card();
gc.setMoney(10000);
gc.setUser_name("唐老鸭");
//调用消费方法
gc.pay(500);
//打印输出
System.out.println(gc.getUser_name()+"会员的余额为:"+gc.getMoney());
}
}
执行效果:
抽象类特征和注意事项
- 类有的成员(成员变量、方法、构造器)抽象类都具备
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
- 不能用abstract修饰变量、代码块、构造器。
- 最重要的特征:得到了抽象方法,失去了创建对象的能力(有得有失)
final和abstract的关系
互斥关系(不能同时使用)
abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。
抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。
模板方法模式
概念:
当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。
实现步骤:
- 定义一个抽象类。2、定义2个方法,一个是模板方法:把相同代码放里面去,不同代码定义成抽象方法
- 子类继承抽象类,重写抽象方法。
案例:
需求:
- 现在有两类学生,一类是中学生,一类是小学生,他们都要写《我的爸爸》这篇作文。
- 要求每种类型的学生,标题第一段和最后一段,内容必须一样。正文部分自己发挥。
- 请选择最优的面向对象方案进行设计。
写作文方法 标题 第一段 正文 最后一段
//父类 学生类
public abstract class Student {
//声明模板方法
public void write() {
System.out.println("标题");
System.out.println("第一段");
//正文部分(每个子类都要自己写)
//模板方法把正文定义成抽象方法,交给具体子类完成
//输出正文部分
System.out.println(writa_tt());
System.out.println("最后一段");
}
public abstract String writa_tt();
}
// 子类中学生类
public class Student_moiddle extends Student{
@Override
public String writa_tt() {
return "中学生作为正文";
}
}
//子类 小学生类
public class Student_child extends Student{
@Override
public String writa_tt() {
return "中学生作文正文——";
}
}
//测试类
public class Test {
public static void main(String[] args) {
//中学生作文
Student_moiddle ms = new Student_moiddle();
ms.write();
System.out.println("--------------------------------------------");
//小学生作文
Student_child cs = new Student_child();
cs.write();
}
}
执行效果:
*模板方法我们是建议使用final修饰的,这样会更专业
如Stuend父类中的模板方法
public final void write() {
System.out.println("标题");
System.out.println("第一段");
//正文部分(每个子类都要自己写)
//模板方法把正文定义成抽象方法,交给具体子类完成
//输出正文部分
System.out.println(writa_tt());
System.out.println("最后一段");
}
模板方法是给子类直接使用的,不是让子类重写的, 一旦子类重写了模板方法,则模板方法就失效了,因此,加上final后可以防止子类重写了模板方法,这样更安全、专业。 |
总结模板方法解决的问题:
- 提高了代码的复用性
- 模板方法已经定义了通用结构,模板方法不能确定的部分定义成抽象方法,交给子类实现,因此,使用者只需要关心自己需要实现的功能即可。