-
前言
在现实世界中,当人们认识世界,也会把现实世界中很多具有相同特征的事物归为一个抽象类。例如,水果是很多种具体植物果实的总称(抽象类),当需要拿出一个水果的实例时,拿出来的不是苹果就是香蕉等具体种类的实例,拿不出只是水果的实例。在需要一个抽象类实例时,只能用某个具体的实例来代替。
Java是抽象和描述现实世界的,因此也提供抽象类,并且其永远不能实例化,其唯一用途是用来继承扩展,这与人们认识现实世界的方式是相同的。
-
抽象类
如果从上而下观察类的层次结构,位于上层的类更具有通用性。一般情况下,人们将这些通用的类作为派生其他类的基类。在Java中,可以使用abstract关键字声明抽象类和抽象方法。下面的例子中将Car类声明为抽象类。
package chapeter04;
abstract class Car
{
private double price;
private String brand;
private int speed;
}
public class Sample4_16
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
}
}
Car类表示汽车,里面有三个成员变量,分别表示汽车都有的价格、品牌、最高是时速等属性。编译代码不会出错,但是想要创建Car类对象,就不能通过编译了:
Car c=new Car();
从上面例子可以看出,抽象类不能实例化,也就是创建对象。
不能把一个类同时标识为abstract和final,这两个关键字有着相反的含义,abstract表示很多类的事物总称,可以再分子类;而final的类一定不能再分子类。
-
抽象方法
抽象方法充当着占位的角色,其具体实现在子类中。抽象方法是只有方法声明,没有方法体,使用abstract关键字来声明的方法。因为抽象方法没有方法体,用分号表示声明结束。例如:public abstract void startup (,,,)
抽象类与抽象方法的关系是,抽象的方法只能存在于抽象类中,例:
package chapeter04;
class Car
{
private double price;
public abstract void startup ();
public double getPrice()
{
return this.price;
}
}
public class Sample4_16
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
}
}
抽象类中可以有非抽象的方法。抽象类中的非抽象方法,往往是抽象类所有子类都具有的,且不会因为子类的不同而不同,如获取价格的getPrice方法。
抽象类中的抽象方法没有方法体,也就是没有方法的实现,是因为这些方法会因为子类的不同而实现不同,例如上面的例子startUp()。
编译上述代码:
从报错可以看出,非抽象类Car中不能有抽象的方法stratUp()。如果想正确通过编译,将Car类声明为abstract即可。
当某类继承自抽象类时,如果其本身不是抽象类,则必须实现所继承类中的抽象方法。抽象类的第一个非抽象子类必须实现其父类的所有抽象方法,其中也包括父类继承的抽象方法,否则变异会报错。
例如,具有启动(startUp)方法的抽象类Car,其每个具体子类都必须实现其自己的专属于某种类型车辆的具体启动(startUp)方法:
package chapeter04;
//定义抽象类Car
abstract class Car
{
//定义抽象方法
public abstract void startUp();
}
//定义抽象类Mazda并继承Car
abstract class Mazda extends Car
{
//定义抽象方法
public abstract void turbo();
}
//定义非抽象类Mazda6并继承Mazda
class Mazda6 extends Mazda
{
//实现抽象方法
public void startUp()
{
System.out.println("调用了Mazda6的启动功能");
}
public void turbo()
{
System.out.println("调用了Mazda6的加速功能");
}
}
//定义非抽象类Mazda3并继承Mazda
class Mazda3 extends Mazda
{
//实现抽象方法
public void startUp()
{
System.out.println("调用了Mazda3的启动功能");
}
public void turbo()
{
System.out.println("调用了Mazda3的加速功能");
}
}
public class Sample4_17
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Mazda6 m6= new Mazda6();
m6.startUp();
m6.turbo();
Mazda3 m3= new Mazda3();
m3.startUp();
m3.turbo();
}
}
上述代码中定义了4个类,Car、Mazda、Mazda6、Mazda3,其中Car、Mazda为抽象类。由于它们分别代表轿车于Mazda轿车,故不能是具体类,因为轿车与Mazda车还能分很多子类。Mazda6和Mazda3分别代表Mazda6与Mazda3的具体车型,故为非抽象类。
Mazda6和Mazda3在继承了Mazda抽象类后分别实现了其中Mazda车特有的加速(turbo)方法,还实现了Mazda从Car继承而来的启动(startUp)方法。可以看出Mazda6和Mazda3的实现是不同的,这也符合现实世界。
从上述例子可以看出,具体的Mazda6和Mazda3实现了启动、加速的方法后,这些方法才有了具体实现。同时,这也是实现面向对象中多态的一种方式,多态的问题,将在下文介绍。
注意:方法永远不能同时声明为abstract和final,二者之间存在相反的含义,abstract修饰的方法必须要重写实现的方法,而final是组织重写的。当然private与abstract也不能同时修饰方法,因为private组织继承,也就阻止了重写实现,这与abstract是冲突的。例如,下面的声明均是错误的:
public abstract final void startUp ();
private abstract void startUp();