《Java从小白到大牛》之第13章 抽象类与接口

栏目: Java · 发布时间: 6年前

内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tonny_guan/article/details/82854642

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tonny_guan/article/details/82854642

《Java从小白到大牛》纸质版已经上架了!!!

《Java从小白到大牛》之第13章 抽象类与接口

设计良好的软件系统应该具备“可复用性”和“可扩展性”,能够满足用户需求的不断变更。使用抽象类和接口是实现“可复用性”和“可扩展性”重要的设计手段。

Java语言提供了两种类:一种是具体类;另一种是抽象了。前面章节接触的类都是具体类。这一节介绍一下抽象类。

抽象类概念 {#-0}

在13.4.1节介绍多态时候,使用过几何图形类示例,其中Figure(几何图形)类中有一个onDraw(绘图)方法,Figure有两个子类Ellipse(椭圆形)和Triangle(三角形),Ellipse和Triangle覆盖onDraw方法。

作为父类Figure(几何图形)并不知道在实际使用时有多少个子类,目前有椭圆形和三角形,那么不同的用户需求可能会有矩形或圆形等其他几何图形,而onDraw方法只有确定是哪一个子类后才能具体实现。Figure中的onDraw方法不能具体实现,所以只能是一个抽象方法。在 Java 中具有抽象方法的类称为“抽象类”,Figure是抽象类,其中的onDraw方法是抽象方法。如图13-1所示类图中Figure是抽象类,Ellipse和Triangle是Figure子类实现Figure的抽象方法onDraw。

《Java从小白到大牛》之第13章 抽象类与接口

提示 在UML类图抽象类和抽象方法字体是斜体的,见图13-1所示中的Figure类和onDraw方法都是斜体的。

抽象类声明和实现 {#-1}

在Java中抽象类和抽象方法的修饰符是abstract,声明抽象类Figure示例代码如下:

//Figure.java文件

package com.a51work6;

public abstract class Figure { ①

// 绘制几何图形方法

public abstract void onDraw(); ②

}

代码第①行是声明抽象类,在类前面加上abstract修饰符。代码第②行声明抽象方法,方法前面的修饰符也是abstract,注意抽象方法中只有方法的声明,没有方法的实现,即没有大括号({})部分。

注意 如果一个方法被声明为抽象的,那么这个类也必须声明为抽象的。而一个抽象类中,可以有0 n个抽象方法,以及0 n具体方法。

设计抽象方法目的就是让子类来实现的,否则抽象方法就没有任何意义,实现抽象类示例代码如下:

//Ellipse.java文件

package com.a51work6;

//几何图形椭圆形

public class Ellipse extends Figure {

//绘制几何图形方法

@Override

public void onDraw() {

System.out.println("绘制椭圆形...");

}

}

//Triangle.java文件

package com.a51work6;

//几何图形三角形

public class Triangle extends Figure {

// 绘制几何图形方法

@Override

public void onDraw() {

System.out.println("绘制三角形...");

}

}

上述代码声明了两个具体类Ellipse和Triangle,它们实现(覆盖)了抽象类Figure的抽象方法onDraw。

调用代码如下:

//HelloWorld.java文件

package com.a51work6;

public class HelloWorld {

public static void main(String[] args) {

// f1变量是父类类型,指向子类实例,发生多态

Figure f1 = new Triangle();

f1.onDraw();

// f2变量是父类类型,指向子类实例,发生多态

Figure f2 = new Ellipse();

f2.onDraw();

}

}

上述代码中实例化两个具体类Triangle和Ellipse,对象f1和f2是Figure引用类型。

注意 抽象类不能被实例化,只有具体类才能被实例化。

使用接口

比抽象类更加抽象的是接口,在接口中所有的方法都是抽象的。

提示 Java 8之后接口中新增加了默认方法,因此“接口中所有的方法都是抽象的”这个提法在Java 8之后是有待商榷。

接口概念 {#-0}

其实13.1.1节抽象类Figure可以更加彻底,即Figure接口,接口中所有方法都是抽象的,而且接口可以有成员变量。将13.1.1节几何图形类改成接口后,类图如图13.2所示。

《Java从小白到大牛》之第13章 抽象类与接口

提示 在UML类图中接口的图标是“I”,见图13-2所示中的Figure接口。类的图标是“C”,见图13-2所示中的Triangle接口。

接口声明和实现 {#-1}

在Java中接口的声明使用的关键字是interface,声明接口Figure示例代码如下:

//Figure.java文件

package com.a51work6;

public interface Figure { ①

//接口中静态成员变量

String name = "几何图形";//省略public static final ②

// 绘制几何图形方法

void onDraw(); //省略public ③

}

代码第①行是声明Figure接口,声明接口使用interface关键字,interface前面的修饰符是public或省略。public是公有访问级别,可以在任何地方访问。省略是默认访问级别,只能在当前包中访问。

代码第②行声明接口中的成员变量,在接口中成员变量都静态成员变量,即省略了public static final修饰符。代码第③行是声明抽象方法,即省略了public关键字。

某个类实现接口时,要在声明时使用implements关键字,当实现多个接口之间用逗号(,)分隔。实现接口时要实现接口中声明的所有方法。

实现接口Figure示例代码如下:

//Ellipse.java文件

package com.a51work6.imp;

import com.a51work6.Figure;

//几何图形椭圆形

public class Ellipse implements Figure {

//绘制几何图形方法

@Override

public void onDraw() {

System.out.println("绘制椭圆形...");

}

}

//Triangle.java文件

package com.a51work6.imp;

import com.a51work6.Figure;

//几何图形三角形

public class Triangle implements Figure {

// 绘制几何图形方法

@Override

public void onDraw() {

System.out.println("绘制三角形...");

}

}

上述代码声明了两个具体类Ellipse和Triangle,它们实现了接口Figure中的抽象方法onDraw。

调用代码如下:

//HelloWorld.java文件

import com.a51work6.imp.Ellipse;

import com.a51work6.imp.Triangle;

public class HelloWorld {

public static void main(String[] args) {

// f1变量是父类类型,指向子类实例,发生多态

Figure f1 = new Triangle();

f1.onDraw();

System.out.println(f1.name); ①

System.out.println(Figure.name); ②

// f2变量是父类类型,指向子类实例,发生多态

Figure f2 = new Ellipse();

f2.onDraw();

}

}

上述代码中实例化两个具体类Triangle和Ellipse,对象f1和f2是Figure接口引用类型。接口Figure中声明了成员变量,它是静态成员变量,代码第①行和第②行是访问name静态变量。

注意 接口与抽象类一样都不能被实例化。

接口与多继承 {#-2}

在C++语言中一个类可以继承多个父类,但这会有潜在的风险,如果两个父类在有相同的方法,那么子类如何继承哪一个方法呢?这就是C++多继承所导致的冲突问题。

在Java中只允许继承一个类,但可实现多个接口。通过实现多个接口方式满足多继承的设计需求。如果多个接口中即便有相同方法,它们也都是抽象的,子类实现它们不会有冲突。

图13-3所示是多继承类图,其中的有两个接口InterfaceA和InterfaceB,从类图中可以见两个接口中都有一个相同的方法void methodB()。AB实现了这两个接口,继承了Object父类。

《Java从小白到大牛》之第13章 抽象类与接口

接口InterfaceA和InterfaceB代码如下:

//InterfaceA.java文件

package com.a51work6;

public interface InterfaceA {

void methodA();

void methodB();

}

//InterfaceB.java文件

package com.a51work6;

public interface InterfaceB {

void methodB();

void methodC();

}

从代码中可见两个接口都有两个方法,其中方法methodB()完全相同。

实现接口InterfaceA和InterfaceB的AB类代码如下:

//AB.java文件

package com.a51work6.imp;

import com.a51work6.InterfaceA;

import com.a51work6.InterfaceB;

public class AB extends Object implements InterfaceA, InterfaceB { ①

@Override

public void methodC() {

}

@Override

public void methodA() {

}

@Override

public void methodB() { ②

}

}

在AB类中的代码第②行实现methodB()方法。注意在AB类声明时,实现两个接口,接口之间使用逗号(,)分隔,见代码第①行。

接口继承 {#-3}

Java语言中允许接口和接口之间继承。由于接口中的方法都是抽象方法,所以继承之后也不需要做什么,因此接口之间的继承要比类之间的继承简单的多。如同4-4所示,其中InterfaceB继承了InterfaceA,在InterfaceB中还覆盖了InterfaceA中的methodB()方法。ABC是InterfaceB接口的实现类,从图可见ABC需要实现InterfaceA和InterfaceB接口中的所有方法。

《Java从小白到大牛》之第13章 抽象类与接口

接口InterfaceA和InterfaceB代码如下:

//InterfaceA.java文件

package com.a51work6;

public interface InterfaceA {

void methodA();

void methodB();

}

//InterfaceB.java文件

package com.a51work6;

public interface InterfaceB extends InterfaceA {

@Override

void methodB();

void methodC();

}

InterfaceB继承了InterfaceA,声明时也使用extends关键字。InterfaceB 中的methodB()覆盖了InterfaceA,事实上在接口中覆盖方法,并没有实际意义,因为它们都是抽象的,都是留给子类实现的。

实现接口InterfaceB的ABC类代码如下:

//ABC.java文件

package com.a51work6.imp;

import com.a51work6.InterfaceB;

public class ABC implements InterfaceB {

@Override

public void methodA() {

}

@Override

public void methodB() {

}

@Override

public void methodC() {

}

}

ABC类实现了接口InterfaceB,事实上是实现InterfaceA和InterfaceB中所有方法,相当于同时实现InterfaceA和InterfaceB接口。

Java 8新特性默认方法和静态方法 {#java-8}

在Java 8之前,尽管Java语言中接口已经非常优秀了,但相比其他面向对象的语言而言Java接口存在如下不足之处:

  1. 不能可选实现方法,接口的方法全部是抽象的,实现接口时必须全部实现接口中方法,哪怕是有些方法并不需要,也必须实现。
  2. 没有静态方法。

针对这些问题,Java 8在接口中提供了声明默认方法和静态方法的能力。接口示例代码如下:

//InterfaceA.java文件

package com.a51work6;

public interface InterfaceA {

void methodA();

String methodB();

// 默认方法

default int methodC() {

return 0;

}

// 默认方法

default String methodD() {

return "这是默认方法...";

}

// 静态方法

static double methodE() {

return 0.0;

}

}

在接口InterfaceA中声明了两个抽象方法methodA和methodB,两个默认方法methodC和methodD,还有声明了静态方法methodE。接口中的默认方法类似于类中具体方法,给出了具体实现,只是方法修饰符是default。接口中静态方法类似于类中静态方法。

实现接口示例代码如下:

//ABC.java文件

package com.a51work6.imp;

import com.a51work6.InterfaceA;

public class ABC implements InterfaceA {

@Override

public void methodA() {

}

@Override

public String methodB() {

return "实现methodB方法...";

}

@Override

public int methodC() {

return 500;

}

}

实现接口时接口中原有的抽象方法在实现类中必须实现。默认方法可以根据需要有选择实现(覆盖)。静态方法不需要实现,实现类中不能拥有接口中的静态方法。

上述代码中ABC类实现了InterfaceA接口,InterfaceA接口中的两个默认方法ABC只是实现(覆盖)了methodB。

调用代码如下:

//HelloWorld.java文件

package com.a51work6.imp;

import com.a51work6.InterfaceA;

public class HelloWorld {

public static void main(String[] args) {

//声明接口类型,对象是实现类,发生多态

InterfaceA abc = new ABC();

// 访问实现类methodB方法

System.out.println(abc.methodB());

// 访问默认方法methodC

System.out.println(abc.methodC()); ①

// 访问默认方法methodD

System.out.println(abc.methodD()); ②

// 访问InterfaceA静态方法methodE

System.out.println(InterfaceA.methodE()); ③

}

}

运行结果:

实现methodB方法...

500

这是默认方法...

0.0

从运行结果可见,代码第①行调用默认方法methodC,是调用类AB中的实现。代码第②行调用默认方法methodD,是调用接口InterfaceA中的实现。代码第③行调用接口静态方法,只能通过接口名(InterfaceA)调用,不能通过实现类ABC调用,可以这样理解接口中声明的静态方法与其他实现类没有任何关系。

抽象类与接口区别

经过前面的学习,广大读者应该对于抽象类和接口所了解,可能会有这样的疑问抽象类和接口有什么区别?本节就回答这个问题。

归纳抽象类与接口区别如下:

  1. 接口支持多继承,而抽象类(包括具体类)只能继承一个父类。
  2. 接口中不能有实例成员变量,接口所声明的成员变量全部是静态常量,即便是变量不加public static final修饰符也是静态常量。抽象类与普通类一样各种形式的成员变量都可以声明。
  3. 接口中没有包含构造方法,由于没有实例成员变量,也就不需要构造方法了。抽象类中可以有实例成员变量,也需要构造方法。
  4. 抽象类中可以声明抽象方法和具体方法。Java 8之前接口中只有抽象方法,而Java 8之后接口中也可以声明具体方法,具体方法通过声明默认方法实现。

提示 学习了接口默认方法后,有些读者还会有这样的疑问,Java 8之后接口可以声明抽象方法和具体方法,这就相当于抽象类一样了吗?在多数情况下接口不能替代抽象类,例如当需要维护一个对象的信息和状态时只能使用抽象类,而接口不行,因为维护一个对象的信息和状态需要存储在实例成员变量中,而接口中不能声明实例成员变量。

本章小结

通过对本章的学习,读者可以了解抽象类和接口的概念,掌握如何声明抽象类和接口,如何实现抽象类和接口。了解Java 8之后的接口的新变化。熟悉抽象类和接口的区别。

配套视频

http://www.zhijieketang.com/classroom/6/courses

配套源代码

https://edu.csdn.net/combo/detail/594

与本书免费版对应的还有一个收费版本:

  1. 进入百度阅读电子书

  2. 进入图灵社区电子书


以上所述就是小编给大家介绍的《《Java从小白到大牛》之第13章 抽象类与接口》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Effective Java

Effective Java

Joshua Bloch / Addison-Wesley Professional / 2018-1-6 / USD 54.99

The Definitive Guide to Java Platform Best Practices—Updated for Java 9 Java has changed dramatically since the previous edition of Effective Java was published shortly after the release of Jav......一起来看看 《Effective Java》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具