抽象类是指在普通类的结构里面增加的组成部分。在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰。而拥有抽象方法的类就是抽象类,抽象类要使用abstract关键字声明。
假设我们有一个动物类,是抽象类,那么要加上关键字abstract,在里面定义一个跑的抽象方法,依然要加上abstract关键字。
public abstract class Animal {
public abstract void run();
}
抽象类可以理解成不完整的设计图,一般作为父类,让子类来继承。当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同,于是该父类就把该行为定义成抽象方法的形式,具体实现交给子类去完成。此时这个类就可以声明成抽象类。
例如:
定义一个动物抽象类,里面定义一个跑的抽象方法。由于不同动物跑的速度或者姿势不同,所以在定义跑这个方法时,并不能写死,也就是明确定义出跑的怎么样。
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.run();
cat.run();
}
}
public abstract class Animal {
public abstract void run();
}
public class Dog extends Animal{
public void run(){
System.out.println("狗跑的更快");
}
}
public class Cat extends Animal {
public void run(){
System.out.println("猫跑的快");
}
}
输出结果:狗跑的更快
猫跑的快
public class Test {
public static void main(String[] args) {
G_card c1 = new G_card();
c1.setMoney(2000);
c1.setName("张三");
c1.pay(300);
System.out.println("剩余:"+ c1.getMoney());
}
}
public abstract class Card {
private String name;
private double money;
public abstract void pay(double money2);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
public class G_card extends Card {
public void pay(double money2) {
System.out.println("您的卡余额为:" + getMoney());
System.out.println("您消费金额为:" + money2);
double rs = money2 * 0.8;
System.out.println("您实际支付:" + rs);
setMoney(getMoney() - rs);
}
}
输出结果:
您卡余额为:2000.0
您消费金额为:300.0
您实际支付:240.0
剩余:1760.0
完全类似与前面提到的动物类的案例,在这个案例中,由于我们有两种不同种类的卡,卡的优惠力度各不相同,故在Card类里的消费方法并不能写死,这时就需要我们的抽象类了。
到这里不知道大伙有没有发现一个问题,不管是前面说到的animal案例和card案例,我们都没有创建其对象??二是创建他们子类的对象??
得到了抽象方法,但是去了创建对象的能力
什么是模板方法模式?当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。
把功能定义成一个所谓的模板方法,放在抽象类中,模板方法中只定义通用且能确定的代码。模板方法中不能决定的功能定义成抽象方法让具体子类去实现。
假设我们不按照模板方法来写,那么在定义中学生和小学生两个类时,我们要分别写开头和结尾,由于开头结尾相同,故产生了屎山代码。
class Student_C {
public void write(){
// 开头
System.out.println("\t\t\t\t《我的爸爸》");
System.out.println("我的爸爸是高富帅......");
// 结尾
System.out.println("我的爸爸太好了!");
}
}
class Student_M {
public void write(){
// 开头
System.out.println("\t\t\t\t《我的爸爸》");
System.out.println("我的爸爸是高富帅......");
// 结尾
System.out.println("我的爸爸太好了!");
}
}
下面,我们定义一个抽象的学生类,把写作正文方法定义在里面,定义成抽象方法,然后把固定的输出开头与结尾的方法定义成普通类(注意,为了体现我们的专业性,要加上final修饰符),在中学生和小学生这两个类里面只需要重写正文的抽象方法即可。
public class Test {
public static void main(String[] args) {
Student_M m = new Student_M();
m.write();
Student_C c = new Student_C();
c.write();
}
}
public abstract class Student {
public final void write(){
// 开头
System.out.println("\t\t\t\t《我的爸爸》");
System.out.println("我的爸爸是高富帅......");
// 正文
System.out.println(writeMain());
// 结尾
System.out.println("我的爸爸太好了!");
}
public abstract String writeMain();
}
public class Student_M extends Student {
public String writeMain() {
return "我的爸爸帅了,是个大明星......";
}
}
public class Student_C extends Student {
public String writeMain() {
return "我的爸爸太有钱了,天天下馆子......";
}
}
输出结果:
《我的爸爸》
我的爸爸是高富帅......
我的爸爸帅了,是个大明星......
我的爸爸太好了!
《我的爸爸》
我的爸爸是高富帅......
我的爸爸太有钱了,天天下馆子......
我的爸爸太好了!
答:为互斥关系
解:abstract定义的抽象类作为模板让子类继承,而final定义的类不能被继承。抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。