Java

1、什么是接口

接口可以看做是一个“纯”抽象类,它只提供一种形式,并不提供实现。

接口中可以规定方法的原型方法名、参数列表以及返回类型,但不规定方法主体;也可以包含基本数据类型的数据成员,但它们都默认为staticfinal

2、接口的作用

  • 是面向对象的一个重要机制
  • 是继承多个设计
  • 建立了类和类之间的“协议”:
    • 将类根据其实现的功能分组用接口代表,而不必顾虑它所在的类继承层次;这样可以最大限度地利用动态绑定,隐藏实现细节
    • 实现不同类之间的常量共享
  • 接口允许我们在看起来不相干的对象之间定义共同行为,如下UML类图所示:

接口的作用

3、接口的语法

1
2
3
[接口修饰符] interface 接口名称 [extends 父接口名]{
//方法的原型声明或静态常量
}

注意:

  • 接口的数据成员一定要有初值,且此值将不能再更改,可以省略final关键字,即接口中每一个方法是隐式抽象的,接口中的方法被隐式的指定为 public abstract(只能是public abstract,其他修饰符都会报错);
  • 接口中的方法必须是抽象方法,不能有方法体,可以省略publicabstract关键字,即接口中的变量会被隐式的指定为public static final变量(并且只能是public,用private修饰会报编译错误)。

4、接口与类的区别

  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法,只能由实现接口的类来实现接口中的方法。
  • 接口不能包含成员变量,除了staticfinal变量。
  • 接口不是被类继承了,而是要被类实现
  • 接口支持多继承

5、抽象类和接口的区别

  • 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。

    注:JDK 1.8 以后,接口里可以有静态方法和方法体了。

  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。

  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

**强调:**接口有以下特性

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的。

例:接口声明

声明一个接口Shape2D,包括π和计算面积的方法原型

1
2
3
4
interface Shape2D {	//声明Shape2D接口
final double pi = 3.14; //数据成员一定要初始化
public abstract double area(); //抽象方法
}

在接口的声明中,允许省略一些关键字,也可声明如下

1
2
3
4
interface Shape2D {
double pi = 3.14;
double area();
}

6、实现接口

(1) 单一接口的实现

不能用new运算符直接产生接口对象。

利用接口设计类的过程,称为接口的实现,使用implements关键字,语法如下:

1
2
3
4
public class 类名称 implements 接口名称 { 
//在类体中实现接口的方法
//本类声明的更多变量和方法
}

注意:

  • 必须实现接口中的所有方法;
  • 来自接口的方法必须声明成public

例:实现接口 Shape2D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Circle implements Shape2D {
double radius;
public Circle(double r) {
radius = r;
}
public double area() {
return (pi * radius * radius);
}
}
class Rectangle implements Shape2D {
int length, width;
public Rectangle(int l, int w) {
length = l;
width = w;
}
public double area() {
return (width * length);
}
}
//测试类
public class InterfaceTester {
public static void main(String args[]) {
Rectangle rect = new Rectangle(5, 6);
System.out.println("Area of rect = " + rect.area());
Circle cir = new Circle(2.0)
System.out.println("Area of cir = " + cir.area());
}
}

运行结果:

1
2
Area of rect = 30.0
Area of cir = 12.56

(2) 多个接口的实现

Java不允许一个类有多个超类

一个类可以实现多个接口,通过这种机制可实现对设计的多重继承。

实现多个接口的语法如下:

1
2
3
4
[类修饰符] class 类名称 implements 接口1, 接口2, … {
//在类体中实现接口的方法
//本类声明的更多变量和方法
}

强调:

  1. 重写接口中声明的方法时,需要注意以下规则:
  • 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
  • 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型
  • 如果实现接口的类是抽象类,那么就没必要实现该接口的方法
  1. 在实现接口的时候,也要注意一些规则:
  • 一个类只能继承一个类,但是能实现多个接口
  • 一个接口能继承另一个接口,这和类之间的继承比较相似。

7、接口类型的引用变量

接口的灵活性就在于“规定了一个类必须做什么,而不管你如何做”。

我们可以定义一个接口类型的引用变量来引用实现接口的类的对象,当这个引用来调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法(实现了方法在运行时的动态绑定)。

例:

1
2
3
4
5
6
7
8
9
public class VariableTester {
public static void main(String args[]) {
Shape2D var1, var2;
var1 = new Rectangle(5, 6);
System.out.println("Area of var1 = " + var1.area());
var2 = new Circle(2.0);
System.out.println("Area of var2 = " + var2.area());
}
}

运行结果:

1
2
Area of rect = 30.0
Area of cir = 12.56

8、接口的扩展

接口可通过扩展的技术派生出新的接口

  • 原来的接口称为超接口(super interface);
  • 派生出的接口称为子接口(sub interface)。

一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。

在Java中,类的多继承是不合法,但接口允许多继承。

在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。

接口扩展的语法:

1
2
3
interface 子接口的名称 extends 超口的名称1, 超接口的名称2, … {
//……
}

注意:实现一个接口的类也必须实现其超接口。

例:Shape 是超接口,Shape2D 与 Shape3D 是其子接口。Circle 类及 Rectangle 类实现接口 Shape2D, 而 Box 类及 Sphere 类实现接口 Shape3D。关系可由如下UML类图表示:

接口的扩展的举例

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//接口声明
//声明Shape接口
interface Shape {
double pi = 3.14159;
void setColor(String str);
}
//声明Shape2D接口扩展了Shape接口
interface Shape2D extends Shape {
double area();
}
//声明Shape3D接口扩展了Shape接口
interface Shape3D extends Shape {
double superficialArea();
double volume();
}

//类声明
//Circle类实现了Shape2D接口
class Circle implements Shape2D {
double radius;
String color;
public Circle(double r) {
radius = r;
color = "white";
System.out.println("New Circle: radius = " + radius);
}
public double area() {
return (pi * radius * radius);
}
public void setColor(String str) {
color = str;
System.out.println("color = " + color);
}
}
//Rectangle类实现了Shape2D接口
class Rectangle implements Shape2D {
int length, width;
String color;
public Rectangle(int l, int w) {
length = l;
width = w;
color = "white";
System.out.println("New Rectangle: length = " + length
+ ", width = " + width);
}
public double area() {
return (width * length);
}
public void setColor(String str) {
color = str;
System.out.println("color = " + color);
}
}
//Box类实现了Shape3D接口
class Box implements Shape3D {
int length, width, height;
String color;
public Box(int l, int w, int h) {
length = l;
width = w;
height = h;
color = "white";
System.out.println("New Rectangle: length = " + length
+ ", width = " + width + ", height = " + height);
}
public double superficialArea() {
return (2 * length * width + 2 * height * width + 2 * length * height);
}
public double volume() {
return (length * width * height);
}
public void setColor(String str) {
color = str;
System.out.println("color = " + color);
}
}
//Sphere类实现了Shape3D接口
class Sphere implements Shape3D {
double radius;
String color;
public Sphere(double r) {
radius = r;
color = "white";
System.out.println("New Sphere: radius = " + radius);
}
public double superficialArea() {
return (4 * pi * radius * radius);
}
public double volume() {
return (4 * pi * radius * radius * radius / 3);
}
public void setColor(String str) {
color = str;
System.out.println("color = " + color);
}
}

//测试类
public class ExtendsInterfaceTester {
public static void main(String[] args) {
Circle cir;
cir = new Circle(2.0);
cir.setColor("blue");
System.out.println("Area of Circle cir is " + cir.area());
System.out.println();

Rectangle rec;
rec = new Rectangle(5, 6);
rec.setColor("red");
System.out.println("Area of Rectangle rec is " + rec.area());
System.out.println();

Box box;
box = new Box(3, 4, 5);
box.setColor("green");
System.out.println("Superficial Area of Box box is " + box.superficialArea());
System.out.println("Volume of Box box is " + box.volume());
System.out.println();

Sphere sph;
sph = new Sphere(15.0);
sph.setColor("yellow");
System.out.println("Superficial Area of Sphere sph is " + sph.superficialArea());
System.out.println("Volume of Sphere sph is " + sph.volume());
System.out.println();
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
New Circle: radius = 2.0
color = blue
Area of Circle cir is 12.56636

New Rectangle: length = 5, width = 6
color = red
Area of Rectangle rec is 30.0

New Rectangle: length = 3, width = 4, height = 5
color = green
Superficial Area of Box box is 94.0
Volume of Box box is 60.0

New Sphere: radius = 15.0
color = yellow
Superficial Area of Sphere sph is 2827.431
Volume of Sphere sph is 14137.155

9、标记接口 △

最常用的继承接口是没有包含任何方法的接口。

标记接口是没有任何方法和属性的接口。它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。

标记接口作用:使对象拥有某个或某些特权。(就是给某个对象打个标、盖个戳)

例如:java.awt.event包中的MouseListener接口继承的java.util.EventListener接口定义如下:

1
2
package java.util;
public interface EventListener {}

标记接口主要用于以下两种目的

  • 建立一个公共的父接口:

    正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。

  • 向一个类添加数据类型:

    这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。