后面的博文,我们将开始Java的常用高级技术学习。
接口(Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口中的所有抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法,接口则包含类要实现的方法。也可以说,一个类的所有方法都是抽象方法,则称为接口。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。一个类可以实现(implement)一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象。
1、接口
接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。
1.1 接口的声明
语法格式如下:
[可见度] interface 接口名称 [extends 其他的类名] {
// 声明变量
// 抽象方法
}
接口有以下特性:
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键子。
- 接口中的方法都是公有的。
举例:
/* 文件名 : Animal.java */
interface Animal {
public void eat();
public void travel();
}
1.2 接口的实现
类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
如果此类是非抽象类,则必须在该类中实现该接口中的所有方法;
如果该类是抽象类,则可以不实现该接口中的所有方法,因为抽象类中允许有抽象方法的存在。
实现一个接口的语法:
... implements 接口名称[, 其他接口, 其他接口..., ...] ...
举例
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
(1)重写接口中声明的方法时,需要注意以下规则:
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
- 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
- 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
(2)在实现接口的时候,也要注意一些规则:
- 一个类可以同时实现多个接口。
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
1.3 接口的继承
接口的继承使用extends关键字,子接口继承父接口的方法。
下面举例Sports接口被Hockey和Football接口继承:
// 文件名: Sports.java
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
// 文件名: Football.java
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
// 文件名: Hockey.java
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。
相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。
2、Comparable接口
下面我们来看下Comparable接口的代码
public interface Comparable
{
int compareTo(Object other);
}
即任何实现 Comparable接口的类都需要包含CompareTo方法,而这个方法的参数必须是一个Object对象。
(1)实际上,现在的Comparable接口已经改进成了泛型类型
public interface Comparable<T>
{
int compareTo(T other);
}
(2)接口中的所有方法都自动属于public,因此,在接口中声明方法时,不必再提供关键字public。
(3)在调用x.compareTo(y)
的时候,当x小于y时,返回一个负数,相等时返回0,否则返回一个正数
(4)接口中可以包含多个方法,可以定义常量,但绝不能含有实例域,也不能在接口中实现方法。提供实例域和方法实现的任务应该由实现接口的那个类来完成。此外,接口中的域都被自动设为public static final。
那么,如果希望使用Arrays类的sort方法对Employee对象数组进行排序,Employee类就必须实现Comparable接口。
为了让类实现一个接口,通常需要:
- 将类声明为实现给定的接口(使用关键字implements)
- 对接口中的所有方法进行定义
(1)将类声明为实现给定的接口,需要使用关键字implements:
class Employee implements Comparable
(2)然后为Employee类提供compareTo方法,假设希望根据Employee的salary进行比较
public int compareTo(Object otherObject)
{
Employee other = (Employee) otherObject;
return Double.compare(salary, other.salary);
}
注意,在接口声明中不必将compareTo方法声明为public(前1);但是在实现接口时,必须将方法声明为public(后2)。
为了避免总是出现Object的类型转换,可以将上面的实现替换为对Comparable<Employee>
接口的实现
class Employee implements Comparable<Employee>
{
public int compareTo(Employee other)
{
return Double.compare(salary, other.salary);
}
···
}
3、接口的特性
接口不是类,尤其不能使用new运算符实例化一个借口
x = new Comparable(···); \\Error
然而,尽管不能构造接口的对象,却能声明接口的变量
Comparable x; \\OK
而且接口变量必须引用实现了接口的类对象
x = new Employee(···); \\OK
4、 接口与类
总结下接口与类的异同点吧
(1)接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在.java结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在.class结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
(2)接口与类的区别:
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量,除了static和final变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多重继承。
5、接口的意义
接口在开发过程中可以快速分离工作内容。
比如调用者在写业务逻辑的时候需要一个功能,可能是数据库访问,或者复杂计算,但是他的工作专注于实现业务逻辑,不想分开精力去做底层实现,那么他只需要先实现一个接口,定义了规范,然后就可以继续他的业务逻辑代码了。
而实现者可以根据这个接口规范,做具体的实现。
这样通过使用接口就可以快速的分离工作内容,达到团队并行工作的目的。
此外,如果规范是通过接口定义的,那么当你这个功能有多个实现时,你只要实现了这个接口,那么可以快速的替换具体实现,做到代码层面的完全可以分离。
总结起来就一句话:接口或者规范可以在开发过程中做到分离。