------- android培训、java培训、期待与您交流! ----------
1. 抽象类
为了说明抽象类,我们先举一个例子,再用代码进行体现。比如,车辆(Vehicle)是一类事物的抽象总称,而轿车(Sedan)和卡车(Truck)是属于车辆的具体现实对象。驾驶轿车的主要任务是运送客人,驾驶卡车的主要任务是运输货物。而车辆这个抽象概念就是从轿车和卡车向上抽象得来的,也就是所谓的抽象类,代码体现,
代码1:
//抽象类
abstract class Vehicle
{
//抽象方法:只抽取功能定义,不抽取功能主体
abstract voiddrive();
}
class Sedan extends Vehicle
{
//定义了一个Truck中的同名方法
void drive()
{
System.out.println("运送客人");
}
}
class Truck extends Vehicle
{
//定义了一个Sedan中的同名方法
void drive()
{
System.out.println("运输货物");
}
}
Vehicle类就是通过将Sedan和Truck类向上抽象得来的抽象类。抽象类通过一个新的关键字abstract进行定义,abstract意思是“抽象”,可以理解为概念性的,没有具体内容的。
Vehicle类中定义了一个没有方法体的drive方法。这个drive方法也是从Sedan和Truck类中向上抽象得来的,抽象的过程,只抽取功能定义(也就是方法名),不抽取功能主体(也就是方法内容),这是因为两者功能的方式相同,目的不同(反映到代码就是实现方式不同)。之所以不再定义方法内容是因为,父类的方法是由子类的同名方法向上抽象得来,目的就是供子类复写用的,因此,方法体没有实际意义。那么这些方法称为抽象方法。
这时候方法的定义格式也会发生变化:
1) 方法体不再以大括号结尾,而是以分号结束。
2) 方法名前也要添加关键词abstract。
小知识点1:
大家记住,Java中的任何语句,不是以分号结束,就是以大括号结束。
2. 抽象类的特点
1) 抽象方法一定在抽象类内。
2) 抽象类和抽象方法必须被abstract关键词修饰。
3) 无法创建抽象类的对象,因为调用没有方法体的抽象方法没有意义,强制通过new关键字创建对象,编译失败。
4) 第二条决定了,也就无法调用抽象类的方法。
5) 若要使用抽象类的方法,就要定义该类的子类,并复写父类的所有抽象方法,定义具体的方法体,创建子类对象调用。如果子类只复写了父类部分抽象方法,那么由于子类从父类继承了其他抽象方法,因此该子类仍然是抽象类。
小知识点2:
区分抽象方法和没有具体方法体的方法。
抽象方法
abstract void f_1();
没有具体方法体的方法
void f_2(){}
相同点;都没有方法体
不同点:f_1不能被调用,而f_2可以被调用,只是没有实际效果;
3. 抽象类中的非抽象方法
继承自同一个抽象父类的多个子类有很多功能相同,目的和实现方式不同的方法,这些方法可以体现每个类的特点。另一方法面,既然同属于一个大类,总是有某些共同之处,对于车辆(Vehicle)来说,都需要停车(Park)等等共性方法。这时候,就可以在抽象父类中定义这样的共性方法,而这些共性方法不再是抽象的,而是定义了具体的方法内容,子类不再需要重新定义,只需要继承就可以使用。比如,
代码2:
abstract class Vehicle
{
//抽象方法
abstract voiddrive();
//非抽象的共性方法
void park()
{
System.out.println(“停车”);
}
}
4. 抽象类和抽象方法的意义
1) 抽象类
上面说了这么多,对于定义抽象类的目的,很大程度就是在指导我们应该如何定义某一类事物,比如这类事物应该具备什么样的属性和行为,而具体的属性值和行为实现方式,由属于这类事物的具体现实对象去决定,这个抽象父类就好比是一个模板,子类照着这个模板去定义即可。
除此以外,抽象类的存在还可以提高代码的扩展性。比如,还是以车辆(Vehicle)为例,可能除了运送客人和运输货物以外,又对车辆有了战斗的需求,这时就有了坦克(Tank),代码体现,
第三,抽象类中的非抽象方法又可以提高代码的复用性,简化代码。
最后,作为特例,可以不在抽象类中定义抽象方法,这么做仅仅是不让该类建立对象。
代码3:
class Tank extends Vehicle
{
void drive()
{
System.out.println(“奔赴战线,打败敌人!”);
}
}
以此类推,有了新的需求就定义属于该类事物范畴的新事物,并定义新事物的特有方法即可。
2) 抽象方法
抽象方法的存在就是强制子类去复写父类的抽象方法。如果我们不定义抽象方法,而是定义一个没有方法体的方法,就像void f(){}这样,那么子类在继承父类以后,从语法上可以不去复写这个方法,而通过编译,而这样做实际上毫无意义;但是,如果定义抽象方法,那么子类在继承父类以后,就必须复写这个方法,否则不能通过编译,在这样一个过程中就定义了子类的特有内容。
5. 抽象类练习
需求:假如我们在开发一个系统时需要对员工进行建模,员工包含3个属性:姓名工号以及工资。经理也是员工,除了含有员工的属性以外,另外还有一个奖金属性。请使用继承的思想设计员工类和经理类。要求类中提供必要的方法进行属性访问。
分析:普通员工和经理都是公司的雇员。那么首先要定义一个抽象类——雇员。雇员类中定义普通员工和经理类中所有的共性属性(并对外提供获取和设置这些属性的方法)以及功能相同而目的和实现方式不同的方法——抽象方法。具体的普通员工类和经理类,继承雇员类,并复写抽象方法体现各自的特征。经理了还要添加奖金属性,并对外提供设置和获取奖金属性的方法。
代码:
代码4:
abstract class staff
{
private String name, id;//为了应对含有字母的工号,将id设为String
private float wages;
Employee(String name, String id, floatwages)
{
this.name = name;
this.id = id;
this.wages = wages;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setID(String id)
{
this.id = id;
}
public String getID()
{
return id;
}
public void setWages(float wages)
{
this.wages = wages;
}
public float getWages()
{
return wages;
}
//定义员工共有的“工作”方法,但是具体的工作内容有具体的子类实现
public abstract void work();
}
class Employee extends staff
{
/*
不必再定义员工的属性,直接继承即可
*/
Employee(String name, String id, floatwages)
{
//调用父类的构造方法初始化子类对象
super(name, id, wages);
}
/*
共性方法直接继承使用即可
*/
//复写work方法,并定义普通员工的特有内容
public void work()
{
System.out.println("Employee work");
}
}
class Manager extends Employee
{
/*
直接继承员工的其他属性,单独定义额外的奖金属性
*/
private float bonus;
Manager(String name, String id, floatwages, float bonus)
{
//除奖金属性以外,其他属性通过父类的构造方法初始化
super(name, id, wages);
//奖金属性单独初始化
this.bonus = bonus;
}
public void setBonus(float bonus)
{
this.bonus = bonus;
}
public float getBonus()
{
return bonus;
}
//复写work方法,并定义经理的特有内容
public void work()
{
System.out.println("ManagerWork");
}
}