大可制作:QQ群:31564239(asp|jsp|php|mysql)

Java Gossip: 接口(interface)类型

表面上看来,接口有点像是完全没有任何方法被实现的抽象类,但实际上两者在语义与应用上是有差别的。“继承某抽象类的类必定是该类的一个子类”,由于同属一个类型,只要父类中也有定义同名方法,您就可以透过父类类型来操作子类实例中被覆盖的方法,也就是透过父类类型进行多态操作,但“实现某接口的类并不被归属于哪一类”,一个对象上可以实现多个接口。

考虑您有一个方法doRequest(),您事先并无法知道什么类型的对象会被传进来,或者是这个方法可以接受任何类型的对象,您想要操作对象上的某个特 定方法,例如doSomething()方法,问题是传进来的对象是任意的,除非您定义一个抽象类并声明doSomething()抽象方法,然后让所 有的类都继承这个抽象类,否则的话您的doRequest()方法似乎无法实现出来,实际上这么作也没有价值。

接口的目的在定义一组可操作的方法,实现某接口的类必须实现该接口所定义的所有方法,只要对象有实现某个接口,就可以透过该接口来操作对象上对应的方法,无论该对象实际上属于哪一个类,像上一段所述及的问题,就要靠要接口来解决。

接口的声明是使用"interface"关键字,声明方式如下:
interface 接口名称 {
    传回类型 方法(参数列);
    传回类型 方法(参数列);

    // ....
}

一 个声明接口的例子如下:

  • IRequest.java
public interface IRequest {
public void execute();
}

接口的方法权限默认都是"public",所以即使方法声明时不指定public仍是默认为public,例如下例与上例是相同的:
  • IRequest.java
public interface IRequest {
void execute();
}

接口默认都是abstract,有无加abstract都一样,以下的声明作用也是相同:
  • IRequest.java
public abstract interface IRequest {
public abstract void execute();
}


当定义类时,可以使用"implements"关键字来一并指定要实现哪个接口,接口中所有定义的方法都要实现,例如:
  • HelloRequest.java
public class HelloRequest implements IRequest {
private String name;

public HelloRequest(String name) {
this.name = name;
}

public void execute() {
System.out.printf("Hello! %s!%n", name);
}
}

  • WelcomeRequest.java
public class WelcomeRequest implements IRequest {
private String place;

public WelcomeRequest(String place) {
this.place = place;
}

public void execute() {
System.out.printf("Welcome to %s!%n", place);
}
}

由于接口中的方法默认都是public,所以实现接口的类中,方法必须声明为public,否则无法通过编译。

来写一个测试程序:

  • Test.java
public class Test {
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
int n = (int) (Math.random() * 10) % 2;
switch (n) {
case 0:
doRequest(
new HelloRequest("caterpillar"));
break;
case 1:
doRequest(new WelcomeRequest("PmWiki"));
}
}
}

public static void doRequest(IRequest request) {
request.execute();
}
}

在这个程序中,即使doRequest()并不知道传入的对象是哪一种类的实例,但它只要知道这个对象的操作接口就可以正确的执行请求,这是接口实现的一个实际应用,也是很常见到的一种应用。

在C++中可以使用多重继承,但在Java中只能单一继承,也就是一次只能继承一个类,Java使用interface来达到某些多重继承的目的,您可 以一次实现多个接口,就像是同时继承多个抽象类(实际上这是C++中多重继承的一个实际运用方式),实现多个接口的方式如下:
public class 类名称 implements 接口1, 接口2, 接口3 {
    // 接口实现
}

当您实现多个接口时,记得您必须实现每一个接口中所定义的方法,由于您实现了多个接口,所以要操作对象时,必要时您必须作“接口转换”,如此程序才能知道如何正确的操作对象,例如假设someObject实现了ISomeInterface1与ISomeInterface2两个接口,则我们可以如下对对象进行接口转换与操作:
ISomeInterface1 obj1 = (ISomeInterface1) someObject;
obj1.doSomeMethodOfISomeInterface1();
 
ISomeInterface2 obj2 = (ISomeInterface2) someObject;
obj2.doSomeMethodOfISomeInterface2();
 
抽象类 中的所有方法都是抽象方法时,它的作用就与接口有些类似(像在C++中,并没有区分抽象类与接口),但记得在Java中只允许单一继承,所以您不能同时 继承多个抽象方法。

事实上在Java里,抽象类中并不会全是抽象方法,这么使用并不适当,在Java中区分抽象类与接口,其在语义上是有所不同的,例如抽象类中允许您 先实现某些方法,而保留一些抽象方法不实现,其应用场合之一是像 Template Method 模式 中介绍的接口定义中的方法则是完全不实现,它只定义方法名称,接口常用于规范统一的操作接口,其应用场合之一是像 Command 模式

接口也可以进行继承的动作,同样也是使用"extends"关键字,例如:
中介绍的,接口定义一组协定,所有实现它的类都必须遵守的协定,接口可以保证实现它的类一定会实现所定义的方法。
public interface 名称 extends 接口1, 接口2 {
    // ...
}

不同于类的是,接口可以同时继承多个接口,这也可以达到类似C++中多重继承的功能,而实现子接口的类必须将所有在父接口和子接口中所定义的方法实做出来。



  • 多态(Polymorphism)操作的应用太多了,从 设 计模式 开始学习会是个不错的选择。
  • 在声明接口的名称时,一个常见的惯例是在名称前加上 'I' ,这明显表示这是一个接口。
  • 我喜欢用接口转换,而不是用转型(Cast),为对象转换一个操作接口,而不是将对象转型。