Java_抽象类
3.8、抽象类(核心)
3.8.1 、抽象类的基本概念
普通类就是一个完善的功能类,可以直接产生对象并且可以使用,里面的方法都是带有方法体的,而抽象类之中最大的特点是包含了抽象方法,而抽象方法是只声明而未实现(没有方法体)的方法,而抽象方法定义的时候要使用abstract关键字完成,而抽象方法一定要在抽象类之中,抽象类要使用abstract关键字声明。
范例:定义一个抽象类
abstract class A { private String info = "Hello World ." ; public void print() { System.out.println(info) ; } public abstract void get() ; // 只声明没有方法体 } |
范例:错误的使用 —— 直接实例化对象
public class Test { public static void main(String args[]) { A a = new A () ; // Test.java:10: 错误: A是抽象的; 无法实例化 } } |
思考:为什么抽象类对象不能够直接new?
一个类的对象实例化之后,可以调用类中的属性和方法,但是抽象类之中的抽象方法没有方法体,如果这样直接调用,那么不就乱了吗。
抽象类的使用原则:
· 抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
· 子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法;
· 抽象类对象可以使用对象的向上转型方式,通过子类来进行实例化操作。
范例:使用抽象类
abstract class A { private String info = "Hello World ." ; public void print() { System.out.println(info) ; } public abstract void get() ; // 只声明没有方法体 } class Impl extends A { public void get() { System.out.println("Hello MLDN .") ; } } public class Test { public static void main(String args[]) { A a = new Impl() ; // 向上转型 a.print() ; // 自己类定义 a.get() ; // 子类负责实现 } } |
通过以上的一个程序,现在就可以清楚的发现,与之前类的继承不一样的是,抽象类定义出了子类必须要覆写的方法,而之前的类子类可以有选择性的来决定是否需要覆写。而且可以发现,抽象类实际上就比普通类多了一些抽象方法而已,其他的定义和普通类完全一样。如果把普通类比喻成一盘炒熟的菜,那么抽象类就是一盘半成品。
关于抽象类的若干种疑问?
· 抽象类能否使用final定义?
不能,因为抽象类必须有子类,final定义的类太监类,不能有子类;
· 抽象类之中能否包含构造方法?
可以,因为抽象类之中除了包含抽象方法之外,还包含了普通方法和属性,而属性一定要在构造方法执行完毕之后才可以进行初始化操作;
· 抽象类之中能否不包含抽象方法?
可以,抽象类之中可以没有抽象方法,但是反过来讲,如果有抽象方法,则一定是抽象类,即使抽象类之中没有抽象方法,也不能够被直接实例化;
· 抽象类能否使用static声明?
abstract class A { private String info = "Hello World ." ; static abstract class B {// 外部类 public abstract void print() ; } } class Impl extends A.B { public void print() { System.out.println("Hello MLDN .") ; } } public class Test { public static void main(String args[]) { A.B b = new Impl() ; b.print() ; } } |
如果定义的是外部抽象类,则不能够使用static声明,可是如果定义的是内部抽象类,那么这个内部的抽象类使用了static声明之后,就表示是一个外部的抽象类。
3.8.2 、抽象类的应用 —— 模板设计模式(体会)
下面首先通过一个简单的程序来分析一下,例如:现在有三种类型:狗、机器人、人;
· 狗具备三种功能:吃、睡、跑;
· 机器人具备两个功能:吃、工作;
· 人具备四个功能:吃、睡、跑、工作。
现在就要求设计一个程序,可以让这三类不同的类型,进行工作。现在给出的三个类实际上并没有任何的联系,唯一的联系就是在于一些行为上。
abstract class Action { public static final int EAT = 1 ; public static final int SLEEP = 3 ; public static final int WORK = 5 ; public static final int RUN = 7 ; public void order(int flag) { switch (flag) { case EAT : this.eat() ; break ; case SLEEP: this.sleep() ; break ; case WORK : this.work() ; break ; case RUN : this.run() ; break ; case EAT + SLEEP + RUN : this.eat() ; this.sleep() ; this.run() ; break ; case EAT + WORK : this.eat() ; this.work() ; break ; case EAT + SLEEP + RUN + WORK : this.eat() ; this.sleep() ; this.run() ; this.work() ; break ; } } public abstract void eat() ; public abstract void sleep() ; public abstract void run() ; public abstract void work() ; } class Dog extends Action { public void eat() { System.out.println("小狗在吃。") ; } public void sleep() { System.out.println("小狗在睡。") ; } public void run() { System.out.println("小狗在跑步。") ; } public void work() {} } class Robot extends Action { public void eat() { System.out.println("机器人喝油。") ; } public void sleep() {} public void run() {} public void work() { System.out.println("机器人在工作。") ; } } class Person extends Action { public void eat() { System.out.println("人在吃饭。") ; } public void sleep() { System.out.println("人在睡觉。") ; } public void run() { System.out.println("人在跑步。") ; } public void work() { System.out.println("人在工作。") ; } } public class Test { public static void main(String args[]) { Action act1 = new Dog() ; act1.order(Action.EAT + Action.SLEEP + Action.RUN) ; Action act2 = new Robot() ; act2.order(Action.EAT + Action.WORK) ; } } |
所有的子类如果要想正常的完成操作,必须按照指定的方法进行覆写才可以,而这个时候抽象类所起的功能就是一个类定义模板的功能。