由于这学期开设了一门课程——《软件构造》是以Java语言为基础,所以便开始学习Java,在这里总结一些笔记来记录学习过程(顺便水分)。
这次总结的笔记内容是多态以及抽象类与接口,多态和接口这两项技术都是用于程序有许多相似类或是同类的变量的情况,这种情况下我们一般就会将同类综合,建立有个具有这些类共同点的类——父类,在我们解决的实际问题时,父类一般被定义为抽象类,这是由于在继承树中越上方的类越抽象;而我们在编写子类时就要在他们各自的特点上来重写父类中的方法,这个时候就要利用到多态和接口技术。
在此之前我们会了解到继承技术,这个比较简单,就不赘述了;那么我们先讲讲多态,多态可以使程序具有很好的扩展性,可以对所有类对象进行通用的处理。
我们假设一个情形,我们要画一个平行四边形,代码如下:
public class Parallelogram {
//实例化保存平行四边形对象的数组对象
public void draw(Parallelogram p){//定义draw方法,参数为本类对象
//SomeSentence
}
}
如果我们又需要定义一个绘制正方形的方法,就需要通过定义一个正方形类来处理正方形对象,这样就会出现代码冗余的缺点;此时我们通过定义一个正方形和平行四边形的综合类,分别处理正方形和平行四边形对象,也没有太大意义。
如果定义一个四边形类,让它处理所有继承该类的对象,根据“向上转型”原则可以是每个继承四边形的类的对象作为draw()方法的参数,然后在draw()方法中作一些限定就可以根据不同图形类对象绘制相应的图形,从而以更为通用的四边形类来取代具体的正方形类和平方四边形类。这样处理能够很好地解决代码冗余问题,同时也易于维护,因为可以加入任何继承父类的子类对象,而父类方法也无须修改。
我们需要创建Quadrangle类,再分别创建两个内部类Square和Parallelogramgle,它们都继承了Quadrangle类。编写draw()方法,该方法接收Quadrangle类的对象作为参数,即使用这两个内部类的父类作为方法参数。在主方法中分别以两个内部类的实例对象作为参数执行draw()方法。具体代码如下:
public class Quadrangle {
//实例化保存四边形对象的数组对象
private Quadrangle[] qtest = new Quadrangle[6];
private int nextindex = 0;
public void draw(Quadrangle q) {
//定义draw()方法,参数为四边形对象
if(nextindex < qtest.length){
qtest[nextindex] = q;
System.out.println(nextindex);
nextindex++;
}
}
public static void main(String[] args) {
//实例化两个四边形对象,用于调用draw()方法
Quadrangle q = new Quadrangle();
//以正方形对象为参数调用draw()方法
q.draw(new Square());
//以平行四边形对象为参数调用draw()方法
q.draw(new Parallelogramgle());
}
}
//定义一个正方形类,继承四边形类
class Square extends Quadrangle {
public Square() {
System.out.println("正方形");
}
}
//定义一个平行四边形类,继承四边形类
class Parallelogramgle extends Quadrangle {
public Parallelogramgle() {
System.out.println("平行四边形");
}
}
我们运行Quadrangle类,获得如下结果:
从本实例的运行结果中可以看出,以不同类对象为参数调用draw()方法可以处理不同的图形问题。使用多态节省了开发和维护时间,因为程序员无须在所有的子类中定义执行相同功能的方法,避免了大量重复代码的开发,同时只要实例化一个继承父类的子类对象即可调用相应的方法,这里只要维护父类中的这个方法即可。
但是当我们的继承书根节点具有两个不同的子树时,例如在抽象图形下有三角形与四边形,四边形下有正方形与平行四边形,即使是使用多态技术还是会有冗余的代码,同时这样的父类局限性很大,也许某个不需要draw()方法的子类也不得不重写draw0方法。如果将draw0方法放置在另外一个类中,这样让那些需要 draw0方法的类继承该类,而不需要drawO方法的类继承图形类,但所有的子类都需要图形类,因为这些类是从图形类中被导出的,同时某些类还需要draw0方法,但是在Java 中规定,类不能同时继承多个类,面临这种问题,接口的概念便出现了。
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。
接口使用interface关键字进行定义,其语法如下:
public interface drawTest {
void draw();//接口内的方法,省略abstract关键字
}
一个类实现一个接口可以使用implements关键字,代码如下:
public class Parallelogram extends Quadrangle implements drawTest {
···//
}
然后我们运用接口技术来修改上面用到了多态技术的代码。
在项目中创建QuadrangleUseInterface类,在类中创建两个继承该类的内部类ParallelogramgleUseInterface和SquareUseInterface;在创建drawTest接口,并使前两个内部类实现该接口;然后在主方法中分别调用这两个内部类的draw()方法。代码如下:
interface drawTest {
public void draw();
}
//定义平行四边形类,该类继承了四边形类,并实现了drawTest接口
class ParallelogramgleUseInterface extends QuadrangleUseInterface implements drawTest {
public void draw() {
System.out.println("平行四边形.draw()");
}
void doAnyThing() {
//SomeSentence
}
}
class SquareUseInterface extends QuadrangleUseInterface implements drawTest {
public void draw() {
System.out.println("正方形.draw()");
}
void doAnyThing() {
//SomeSentence
}
}
class AnyThingUseInterface extends QuadrangleUseInterface {
void doAnyThing() {
//SomeSentence
}
}
public class QuadrangleUseInterface {
public void doAnyThing() {
//SomeSentence
}
public static void main(String[] args) {
drawTest[] d = {new SquareUseInterface(), new ParallelogramgleUseInterface()};
for (int i = 0; i < d.length; i++) {
d[i].draw();
}
}
}
在本实例中,平行四边形类与四边形类分别实现了 drawTest接口并继承了四边形类,所以需要覆盖接口中的方法。在调用draw()方法时,首先将平行四边形类对象与正方形类对象向上转型为drawTest接口形式。这里也许很多读者会有疑问,接口是否可以向上转型?其实在 Java 中无论是将一个类向上转型为父类对象,还是向上转型为抽象父类对象,或者向上转型为该类实现接口,都是没有问题的。然后使用 d[i]数组中的每一个对象调用draw(),由于向上转型,所以di]数组中的每一个对象分别代表正方形类对象与平行四边形类对象,最后结果分别调用正方形类与平行四边形类中覆盖的draw()方法。
这就是这次关于多态以及抽象类与接口的相关知识总结,由于后面的实验中这些都是基础知识,所以记下来加深记忆。