在之前的博客多态部分写过关于父类的引用可以调用子类对象的内容,但是可能理解不够深刻,没有理解精髓,今天再叙述一下自己的体会。
贴一个对抽象类Shapes具体化的例子,其中Shapes是一个抽象类,有计算面积和周长的抽象方法。还有一些数据成员,用以之后的复用
import java.awt.*;
import java.applet.*;
abstract class Shapes
{
protected int x,y,k;
protected double m;
public Shapes(int x,int y,int k,double m)
{this.x=x; this.y=y;
this.k=k; this.m=m;
}
abstract public double getArea();
abstract public double getPerimeter();
}
class Rect extends Shapes
{ public double getArea()
{ return(k*m); }
public double getPerimeter()
{ return(2*k+2*m);}
public Rect(int x,int y,int width,int height)
{ super(x,y,width,height);}
}
class Triangle extends Shapes
{ public double getArea()
{return(Math.sqrt(m*( m-k)*( m-x)*(m-y)));}
public double getPerimeter()
{return(k+x+y);}
public Triangle(int baseA,int baseB,int baseC)
{ super(baseA, baseB, baseC,0);
//m充当了周长的一半
m= (baseA+ baseB+ baseC)/2.0;
}
}
class Circle extends Shapes
{ public double getArea()
//Math是java.lang包中的类,PI是静态其属性,其值为Π
{return(m* m *Math.PI);}
public double getPerimeter()
{return(2*Math.PI* m);}
public Circle(int x,int y,int width)
{
//m充当了半径的角色,k充当了直径
super(x,y, width, width/2.0);
}
}
public class RunShape extends Applet
{ Rect rect=new Rect(5,15,25,25);
Triangle tri=new Triangle(5,5,8);
Circle cir =new Circle(13,90,25);
public void paint(Graphics g)
{
//绘制矩形,输出矩形的面积和周长
g.drawRect(rect.x,rect.y,rect.k,(int)rect.m);
g.drawString("Rect Area:"+rect.getArea(),50,35);
g.drawString("Rect Perimeter:"+rect.getPerimeter(),50,55);
//输出三角形的面积和周长
g.drawString("Triangle Area:"+tri.getArea(),50,75);
g.drawString("Triangle Perimeter:"+tri.getPerimeter(),50,95);
//绘制圆,输出圆的面积和周长
g.drawOval(cir.x-(int)cir.k/2,cir.y-(int)cir.k/2,cir.k,cir.k);
g.drawString("Circle Area:"+cir.getArea(),50,115);
g.drawString("Circle Perimeter:"+cir. getPerimeter(),50,135);
}
}
这里需要着重注意的是RunShape这个类,它要分别进行矩形,三角形,圆形三个类的面积和周长的计算,它在这里分别初始化了矩形,三角形和圆形的引用,反复调用它们各自的getArea(),getPerimeter()方法,程序代码很长而且不能复用。此时结合刚刚提到的多态性之一,父类的引用可以指向子类的对象,因此可以将所有形状的求面积和求周长的方法统一起来。如下:
public class RunShape extends Applet
{
Rect rect=new Rect(5,15,25,25);
Triangle tri=new Triangle(5,5,8);
Circle cir=new Circle(13,90,25);
//增加两个方法,注意抽象类的声明为s,ab为字符串输出的坐标。
//getClass.getName是得到对象对应的类名。
private void drawArea(Graphics g,Shapes s,int a,int b)
{g.drawString(s.getClass().getName()+" Area"+s.getArea(),a,b);}
private void drawPerimeter (Graphics g,Shapes s,int a,int b)
{g.drawString(s.getClass().getName()+" Perimeter"+s.getPerimeter(),a,b);}
public void paint(Graphics g)
{ g.drawRect(rect.x,rect.y,rect.k,(int)rect.m); //1
drawArea (g,rect,50,35); //2
drawPerimeter(g,rect,50,55); //3
drawArea (g, tri,50,75); //4
drawPerimeter(g,tri,50,95); //5
g.drawOval(cir.x-(int)cir.k/2,cir.y-(int)cir.k/2,cir.k,cir.k); //6
drawArea (g, cir,50,115); //7
drawPerimeter(g,cir,50,135); //8
}
}
此时将各种形状求面积和周长的方法统一了,直接用父类Shapes的引用s调用相应的方法,此时,程序复用性能大大增强,而且不用去初始化各个子类形状的引用,再和其对应的对象关联起来。
这就是抽象类一个很大的用处,我们往往想用其型,而不是它的方法。这也是java的精髓之一。