抽象类
当编写一个类时,常常会为该类定义一些方法。但在某些时候,某个父类只知道子类应该包含怎样的方法,但无法准确地知道这些子类如何实现这些方法。这时候我们就可以使用抽象方法:只有方法签名,没有方法实现的方法
抽象类和抽象方法
抽象方法和抽象类必须使用abstract修饰符来定义。
有抽象方法的类只能被定义为抽象类。
抽象类里面可以没有抽象方法。
具体规则如下:
1. 抽象方法和抽象类都必须使用abstract修饰,抽象方法不能有方法体
2. 抽象类不能被实例化,“生来就是当爹的”
3. 抽象类可以包含成员变量,方法(普通方法和抽象方法),构造器,初始化块,内部类(接口,枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其他类调用。
4. 含有抽象方法的类只能被定义为抽象类
下面我们来看一个例子,首先我们定义一个抽象类Shape,并为其定义了两个成员方法
package the6;
public abstract class Shape {
{
System.out.println("执行shape的初始化块。。。");
}
private String color;
//定义一个计算周长的抽象方法
public abstract double calParimeter();
//定义一个返回形状的抽象方法
public abstract String getType();
//定义Shape的构造器,该构造器并不是用于创建Shape对象的,而是用于被子类调用的
public Shape(){}
public Shape(String color)
{
System.out.println("执行shape的构造器");
this.color = color;
}
public void setColor(String color)
{
this.color = color;
}
public String getColor()
{
return this.color;
}
}
然后我们又定义了两个子类。分别是三角形和圆形
package the6;
public class Triangle extends Shape {
private double a;
private double b;
private double c;
public Triangle(String color, double a, double b, double c )
{
super(color);
this.setSides(a,b,c);
}
private void setSides(double a, double b, double c) {
if(a >= b+c || b >= a+c ||c >= b+a){
System.out.println("三角形两边之和必须大于第三边");
return;
}
this.a = a;
this.b = b;
this.c = c;
}
@Override
public double calParimeter() {
return a+b+c;
}
@Override
public String getType() {
return "三角形";
}
}
package the6;
import org.omg.CORBA.TRANSIENT;
public class Circle extends Shape{
private double radius;
public Circle(String color, double radius)
{
super(color);
this.radius = radius;
}
@Override
public double calParimeter() {
return 2 * Math.PI * radius;
}
@Override
public String getType() {
return "圆形";
}
public static void main(String[] args){
Triangle tr = new Triangle("红色", 3, 4, 5);
Circle ci = new Circle("蓝色",8);
System.out.println(tr.getType());
System.out.println(tr.calParimeter());
System.out.println(ci.getType());
System.out.println(ci.calParimeter());
}
}
从运行的结果来看,我们在main()函数中产生了两个子类的对象,首先都运行了父类的初始化块,并运行了父类的构造器(使用super关键字),然后这两个对象各自调用了自己的两个方法。
事实上,我们可以这样改写我们的main()函数。
public static void main(String[] args){
Shape tr = new Triangle("红色", 3, 4, 5);
Shape ci = new Circle("蓝色",8);
System.out.println(tr.getType());
System.out.println(tr.calParimeter());
System.out.println(ci.getType());
System.out.println(ci.calParimeter());
}
现在我们的两个对象的编译时类型和运行时类型不同了,也就是说,发生了多态。但是我们的运行结果是一样的。因为我们在Shape中也定义了getType()和calParimeter()函数,所以我们不用对这两个对象进行强制类型转换就可以调用这两个函数(并且表现为各自子类的函数)。
利用抽象类和抽象方法的优势,可以更好地发挥多态的优势,使程序更灵活
final和abstract永远无法同时使用
抽象类的作用
从语义的角度来看,抽象类是从多个具体的类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类设计的随意性。
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上扩展和改造。
另一种抽象类模板模式设计的方法是,我们定义一个抽象的父类,并提供一个普遍的方法,但是这个方法的运行依赖于另一个方法,而这个方法则不是普遍的(不同的子类有不同的方案);因此我们把这个不普遍的方法定义为抽象方法,并将其实现推迟到各个子类中。