十三、抽象类
在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承和多态处理。回想继承和多态原理,继承树中越是在上方的类越抽象,例如鸽子类继承鸟类、鸟类继承动物类等等。在多态机制中,并不需要将父类初始化对象,我们需要的只是子类对象,所以在JAVA语言中设置抽象类不可以实例化对象,因为图形类不能抽象出任何一种具体图形,但是他的子类可以。
-
抽象类的语法如下:
public abstract class Test { abstract void testAbstract(); //定义抽象方法 }
其中,abstract是定义抽象类的关键字。使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承之外没有任何意义。
反过来说,如果声明一个抽象的方法,就必须将承载这个抽象方法的类定义为抽象类,不可能在非抽象类中获取抽象方法。换句话说,只要类中有一个抽象方法,此类就被标记为抽象类。
抽象类案例:
chouxiang1.java
package lianxi2;
public class chouxiang1
{
public static void main(String[] args)
{
color c1=new red();
color c2=new blue();
c1.show();
c2.show();
}
}
color.java
package lianxi2;
public abstract class color
{
public void show()
{
}
}
class red extends color
{
public void show()
{
System.out.println("我是红色");
}
}
class blue extends color
{
public void show()
{
System.out.println("我是蓝色");
}
}
运行结果:
- 可以看到该抽象父类中的方法没有任何意义,只是给子类继承用的。子类继承父类的方法后可以重新改写。在chouxiang1.java中如果加上语句
color c3=new color();
则编译会出错,因为抽象类不能被实例化。
抽象方法案例:
chouxiang2.java
package lianxi2;
public class chouxiang2
{
public static void main(String[] args)
{
teacher tony=new mathteacher();
teacher john=new englishteacher();
tony.teaching();
john.teaching();
}
}
teacher.java
package lianxi2;
public abstract class teacher
{
public abstract void teaching();
}
class mathteacher extends teacher
{
public void teaching()
{
System.out.println("这节课讲三角函数");
}
}
class englishteacher extends teacher
{
public void teaching()
{
System.out.println("open the book");
}
}
运行结果:
如何使用抽象方法案例:
chouxiang3.java
package lianxi2;
public class chouxiang3
{
public static void main(String[] args)
{
seagull lina=new seagull("白色");
lina.move();
lina.eat();
lina.growferther();
lina.reproduce();
System.out.println();
chicken xiaoji=new chicken("黄色");
xiaoji.move();
xiaoji.eat();
xiaoji.growferther();
xiaoji.reproduce();
}
}
animal.java
package lianxi2;
public abstract class animal
{
public animal()
{
System.out.println("创建了一个动物类");
}
public abstract void eat();
abstract public void reproduce();
}
bird.java
package lianxi2;
public abstract class bird extends animal
{
String ferther;
public bird(String ferther)
{
System.out.println("创建了一个鸟类");
this.ferther=ferther;
}
public void growferther()
{
System.out.println("长满"+ferther+"羽毛");
}
abstract public void move();
public void reproduce()
{
System.out.println("下蛋");
}
}
seagull.java
package lianxi2;
public class seagull extends bird
{
public seagull(String ferther)
{
super(ferther);
System.out.println("我是一只海鸥");
}
public void move()
{
System.out.println("海鸥飞翔");
}
public void eat()
{
System.out.println("海鸥吃鱼");
}
}
chicken.java
package lianxi2;
public class chicken extends bird
{
public chicken(String ferther)
{
super(ferther);
System.out.println("我是一只小鸡");
}
public void move()
{
System.out.println("小鸡快跑");
}
public void eat()
{
System.out.println("小鸡啄米");
}
}
运行结果:
- 可以看到该程序是一个三层结构,animal和bird是抽象类,因为动物和鸟都有很多种,无法具体到某个物种,seagull和chicken不是抽象类,为具体的某个物种。另外有三个抽象方法:move()、eat()、reproduce()。
十四、接口
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。
如图可以看到这是通常的继承关系,子类继承父类的所有方法。但是如果三角形类不需要void draw()这个方法,那只能删除父类(图形类)的void draw()方法,但是一旦删除父类的这个方法后,其他需要该方法的子类也就无法继承这个方法了,这就造成了功能缺失。
所以就引入了接口这个概念,让需要void draw()这个方法的子类继承接口中的这个方法就行。
-
接口使用interface关键字进行定义,其语法如下:
public interface drawTest { void draw(); }
需要注意的是,在接口中,方法必须被定义为public或者abstract形式,其他修饰权限不能被JAVA编译器认可。或者说,即使不将该方法声明为public形式,它也是public。
在接口中定义的任何字段都自动是static和final的。
多态与接口结合的案例:
package lianxi2;
interface drawTest { // 定义接口
public void draw(); // 定义方法
}
// 定义平行四边形类,该类继承了四边形类,并实现了drawTest接口
class ParallelogramgleUseInterface extends QuadrangleUseInterface
implements drawTest {
public void draw() { // 由于该类实现了接口,所以需要覆盖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() {
}
}
public class QuadrangleUseInterface { // 定义四边形类
public void doAnyTthing() {
// SomeSentence
}
public static void main(String[] args) {
drawTest[] d = { // 接口也可以进行向上转型操作
new SquareUseInterface(), new ParallelogramgleUseInterface() };
for (int i = 0; i < d.length; i++) {
d[i].draw(); // 调用draw()方法
}
}
}
运行结果:
- 在这个实例中,正方形类与平行四边形类分别实现了drawTest接口并继承了四边形类,所以需要覆盖接口中的方法。在调用draw()方法时,首先将平行四边形类对象与正方形类对象向上转型为drawTest接口形式。然后使用d[i]数组中的每一个对象调用draw(),由于向上转型,所以d[i]数组中的每一个对象分别代表正方形类对象和平行四边形类对象,最后结果分别调用正方形类和平行四边形类中覆盖的draw()方法。
接口与继承
JAVA中不允许出现多重继承,但是使用接口可以实现多重继承。一个类可以同时实现多个接口,因此可以将所有需要继承的接口放置在implements关键字后并用逗号隔开。但是这可能会在一个类中产生庞大的代码量,因为要继承一个接口时需要实现接口中所有的方法。
-
多重继承的语法如下:
class 类名 implements 接口1,接口2,···接口n