随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
1、抽象类的使用
1、abstract:抽象的
2、abstract可以用来修饰的结构:类、方法
3、abstract 修饰类:抽象类
- 此类不能被实例化
- 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化全过程)
开发中,都会提供抽象类的子类,让子类对象实例化,实现相关的操作
4、abstract 修饰方法:抽象方法
抽象方法,只有方法的声明,没有方法体。
- 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法。
-
5、abstract 使用上的注意点
abstract不能修饰变量,代码块,构造器;
- abstract 不能用来修饰私有方法、静态方法、final的方法、final的类
2、抽象类应用
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
问题:卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同。Vehicle 类不能提供计算方法,但子类可以。 ```java /* Java 允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提 供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。- Vehicle 是一个抽象类,有两个抽象方法。
- 注意:抽象类不能实例化 new Vihicle()是非法的
*/
public abstract class Vehicle{
public abstract double calcFuelEfficiency();//计算燃料效率的抽象方法
public abstract double calcTripDistance();//计算行驶距离的抽象方法
}
public class Truck extends Vehicle{
public double calcFuelEfficiency(){
} public double calcTripDistance(){//写出计算卡车的燃料效率的具体方法
} } public class RiverBarge extends Vehicle{ public double calcFuelEfficiency() {//写出计算卡车行驶距离的具体方法
} public double calcTripDistance( ) {//写出计算驳船的燃料效率的具体方法
} }//写出计算驳船行驶距离的具体方法
<a name="vNhfM"></a># 3、创建抽象类的匿名子类对象```java/** 抽象类的匿名子类**/public class PersonTest {public static void main(String[] args) {method(new Student()); //匿名对象Worker worker = new Worker();method1(worker); //非匿名的类非匿名的对象method1(new Worker()); //非匿名的类匿名的对象System.out.println("*********************");//创建了一个匿名子类的对象:pPerson p = new Person(){@Overridepublic void eat() {System.out.println("吃东西");}@Overridepublic void breath() {System.out.println("呼吸空气");}};method1(p);System.out.println("**********************");//创建匿名子类的匿名对象method1(new Person(){@Overridepublic void eat() {System.out.println("吃零食");}@Overridepublic void breath() {System.out.println("云南的空气");}});}public static void method1(Person p){p.eat();p.walk();}public static void method(Student s){}}class Worker extends Person{@Overridepublic void eat() {}@Overridepublic void breath() {}}
4、多态的应用:模板方法设计模式(TemplateMethod)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式
/** 抽象类的应用:模板方法的设计模式*/public class TemplateTest {public static void main(String[] args) {SubTemlate t = new SubTemlate();t.sendTime();}}abstract class Template{//计算某段代码执行所需花费的时间public void sendTime(){long start = System.currentTimeMillis();code(); //不确定部分,易变的部分long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end - start));}public abstract void code();}class SubTemlate extends Template{@Overridepublic void code() {for(int i = 2;i <= 1000;i++){boolean isFlag = true;for(int j = 2;j <= Math.sqrt(i);j++){if(i % j == 0){isFlag = false;break;}}if(isFlag){System.out.println(i);}}}}
//抽象类的应用:模板方法的设计模式public class TemplateMethodTest {public static void main(String[] args) {BankTemplateMethod btm = new DrawMoney();btm.process();BankTemplateMethod btm2 = new ManageMoney();btm2.process();}}abstract class BankTemplateMethod {// 具体方法public void takeNumber() {System.out.println("取号排队");}public abstract void transact(); // 办理具体的业务 //钩子方法public void evaluate() {System.out.println("反馈评分");}// 模板方法,把基本操作组合到一起,子类一般不能重写public final void process() {this.takeNumber();this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码this.evaluate();}}class DrawMoney extends BankTemplateMethod {public void transact() {System.out.println("我要取款!!!");}}class ManageMoney extends BankTemplateMethod {public void transact() {System.out.println("我要理财!我这里有 2000 万美元!!");}}
模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的影子,比如常见的有:
- 数据库访问的封装
- Junit 单元测试
- JavaWeb 的 Servlet 中关于 doGet/doPost 方法调用
- Hibernate 中模板程序
- Spring 中 JDBCTemlate、HibernateTemplate 等
