【JAVA进化论】LV2-5:接口

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就有必要声明为抽象类。

简单来总结下:接口类似一个只有抽象方法的抽象类,就像抽象类一样,它无法被实例化,必须要有实现类它才会有意义。

一、接口的定义&用法

1.1:例子&用法

用最简单最好理解的方式来说,所谓接口就是一个只有抽象方法的”抽象类“(这里只是类比,接口不是类),接口跟抽象类、抽象类跟普通类之间的区别和意义,我们放到第二节来讲,这里看个案例:

代码块1
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
//通过interface关键词定义接口
public interface TrafficTools { //交通工具接口,用来抽象符合交通工具所具备的一系列行为标准

String move(); //所有的交通工具都具备移动这一标准

}


//下面是实现了该接口的两种具体的交通工具
//------------------------------------------------------------------------------------------------

//使用implements关键词实现接口
public class HighSpeedRailway implements TrafficTools { //高铁是一种交通工具,符合交通工具所定义的标准

private String speed = "306km/h"; //高铁属性你就随意抽象,这里抽象了一个叫速度的属性出来

@Override
public String move() {
return "靠行走在" + railway() + "上的火车,以" + speed + "的速度";
}

public String railway() { //高铁是走在高铁铁轨上的
return "高速轨道铁路";
}

public void setSpeed(String speed) {
this.speed = speed;
}
}


public class Plane implements TrafficTools { //飞机是一种交通工具,符合交通工具所定义的标准

private String company = "华航"; //飞机属性你就随意抽象,比如飞机型号、名称、所属公司,按需定义

@Override
public String move() { //实现move方法
return "靠" + company + "的飞机,以" + fly() + "的方式";
}

public String fly() { //具体的移动方式,飞机当然是靠飞了
return "飞行";
}

public void setCompany(String company) {
this.company = company;
}
}

接口不允许有属性,可以简单理解接口是定义一系列动作(即方法)的标准,任意符合这个标准的类都可以实现这个接口,比如例子中的飞机和高铁类,都可以实现TrafficTools接口,因为它们都是交通工具,都有move这一基本标准。现在定义好了交通工具,让我们再定义旅游类,它是一个抽象类,抽象出来了旅行所具备的属性和方法:

代码块2
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
public abstract class Tour {

private String start; //出发点

private String end; //终点

private String name; //主角们的名字

private TrafficTools tools; //旅行需要一种交通工具

public abstract String kind(); //旅行方式,这个需要子类去实现,旅游种类:度假、蜜月、探亲等

public abstract String play(); //玩了什么?同样旅行类无法实现,只能靠子类去实现

public String getTour() { //输出对这次旅行的描述
return kind() + tools.move() + ",从" + start + "出发,抵达" + end + play();
}

//属性的设置方法
public void setStart(String start) {
this.start = start;
}

public void setEnd(String end) {
this.end = end;
}

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setTools(TrafficTools tools) {
this.tools = tools;
}
}


//下面是两个实现了旅行类的子类,分别代表着不同的旅行类型
//----------------------------------------------------------------------------------------------------------------
public class AloneTour extends Tour { //个人旅行是旅行的一种

@Override
public String kind() {
return super.getName() + "的个人旅行";
}

@Override
public String play() {
return "完成了自己的个人旅行,顺便修了个仙儿~";
}
}


public class HoneyMoonTour extends Tour { //蜜月旅行是旅行的一种

@Override
public String kind() {
return super.getName() + "的蜜月旅行";
}

@Override
public String play() {
return "玩了专为情侣准备的蜜月项目";
}
}

让我们来具体测试下:

代码块3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) {
Tour myAloneTour = new AloneTour(); //打算开始一次个人旅行
myAloneTour.setStart("东京都"); //始发地
myAloneTour.setEnd("雏见泽"); //目的地
myAloneTour.setName("前原圭一"); //需要进行这次旅行的主角名字
//选择一种交通工具
TrafficTools tools = new HighSpeedRailway(); //选择高铁(可以看到,接口类的引用变量也可以接收自己实现类的对象实例)
myAloneTour.setTools(tools);
System.out.println(myAloneTour.getTour()); //输出这次旅行的内容

Tour hmTour = new HoneyMoonTour(); //打算开始一场蜜月旅行
hmTour.setStart("木叶忍者村"); //始发地
hmTour.setEnd("涡の国"); //目的地
hmTour.setName("漩涡鸣人&日向雏田"); //需要进行这次旅行的主角名字
//选择一种交通工具
TrafficTools tools2 = new Plane(); //选择飞机
hmTour.setTools(tools2);
System.out.println(hmTour.getTour()); //输出这次旅行的内容
}

上方代码输出如下:

代码块4
1
2
前原圭一的个人旅行靠行走在高速轨道铁路上的火车,以306km/h的速度,从东京都出发,抵达雏见泽完成了自己的个人旅行,顺便修了个仙儿~
漩涡鸣人&日向雏田的蜜月旅行靠华航的飞机,以飞行的方式,从木叶忍者村出发,抵达涡の国玩了专为情侣准备的蜜月项目

看完本例,你可以了解接口的基本用法。

非常重要的一点:接口支持多继承,一个类可以同时实现多个接口

举个非常简单的例子:

代码块5
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
public interface A {

void a();

}


public interface B {

void b();

}


public interface C extends A, B { //接口的多继承,这时如果一个类要想实现C,则需要同时实现ABC里的方法

void c();

}


public interface D {

void d();

}


public class E implements C, D { //一个类可以同时实现多个接口,接口里所有的方法均需要实现
@Override
public void c() {

}

@Override
public void a() {

}

@Override
public void b() {

}

@Override
public void d() {

}
}


public abstract class F implements C, D { //同样的,抽象类也可以同时实现多个接口,但由于抽象类的特性,它可以不用实现接口里的方法,全员叫给它的子类去做,当然,也可以选择实现,如下方c方法

abstract void f();

void f2() {

}


@Override
public void c() {

}
}


public class G extends F { //继承了上方抽象类的子类,需要同时实现父类的抽象方法f以及父类继承了的接口且没有进行实现的方法
@Override
void f() {

}

@Override
public void a() {

}

@Override
public void b() {

}

@Override
public void d() {

}
}

接口、抽象类、类之间的关系不管依赖多么复杂,当方法发生调用时,均遵循上一章节讲的”就近调用“规则。

1.2:接口与类相似点

  • 一个接口可以有多个方法。
  • 接口文件保存在.java结尾的文件中,文件名使用接口名。
  • 接口的字节码文件保存在.class结尾的文件中。
  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中。

1.3:接口与类的区别

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

二、类、抽象类、接口之间的区别

在java的世界里,一切皆对象,而对象又是根据类的模板生成的符合类定义的一个个体,所以类是对一类事物的具体抽象。

抽象类无法被实例化,它是为普通类服务的,简单来说,普通类用来抽象真实存在的事物,给它们分类(猫、狗、数据库对象等),而抽象类是位于普通类上层的用来给类分类的,比如猫狗,都可以拆分成猫类,狗类,但是猫和狗具有相同意义的属性和方法,例如年龄、吃饭睡觉等,这些就可以再次被分类,成为猫和狗的父类,比如动物,你会发现不光猫狗具备这些被抽象出来的属性和方法,日后如果定义一个人类,同样也是符合的,抽象类就是为类分类而生的,它必须要有子类继承才有意义,抽象类可以自己定义方法的实现,也可以把一些方法全部交给子类去实现,如果一个抽象类里并不存在被抽象出来的属性,只有一些行为规范,而且这些行为规范抽象类自己实现没有意义,只能交给子类去实现,这个时候就可以将抽象类里的方法全部定义成抽象方法(现在很像接口了对吧),而接口就是这种位于上层里仅定义行为规范的一种结构。