Java语言提供了一种接口(interface)机制。这种接口机制使Java的面向对象编程变得更加灵活。我们可以用接口来定义一个类的表现形式,但接口不能包含任何实现。在《Thinking in Java》一书中,作者对接口有这样的描述:“接口(interface)比抽象(abstract)的概念更进了一步。你可以把一个接口看成是一个纯的抽象类。”我认为作者对接口的这一解释再准确不过了。
理解并用好接口机制将帮助我们更好的掌握Java这种面向对象的编程语言。下面我们来讨论一下接口的使用规则以及相关的应用。
一、接口的定义及实现
定义接口和定义类相似,只是要把class关键字换为interface。定义方法时只需要方法名,返回类型和参数列表,不能有方法体。接口中可以定义字段,这些字段都被暗指为static和final,因此应该根据需要先定好这些字段的值。例如:
public interface Flyable {void fly();}
public interface Talkable {void talk();} public interface Message { int MAX_SIZE = 4096; String getMessage(); } |
public class Parrot implements Flyable, Talkable
{ public void fly() { System.out.println("Flying like a parrot…"); } public void talk() { System.out.println("Hello! I am a parrot!"); } } public class TextMessage implements Message {String message; public void setMessage(String msg) {message = msg; if (message.length() > MAX_SIZE) message = message.substring(0, MAX_SIZE);} public String getMessage() {return message; } } |
在Parrot(鹦鹉)例子中,我们用接口Flyable来表示飞行能力,Talkable表示说话能力,但它们并不包含具体实现。而Parrot同时具有这两种能力,所以我们为Parrot类同时实现了Flyable和Talkable这两个接口。同样我们还可以定义一个Swallow(燕子)类,但燕子只有飞行能力,所以我们只需要为Swallow实现Flyable就行了。因为它们各自的的飞行方法有所不同,所以它们有各自关于飞行的具体实现。
另外,正因为一个类可以同时实现多个接口,使得Java的面向对象特性变得非常灵活。运用这种特性,我们可以实现类似C++语言中多继承那样的特性,甚至更灵活的一些特性。下面我们来讨论一下接口在实际中的应用。
二、用接口来定义一些全局变量
因为接口内的字段都是static和final的,所以我们可以很方便的利用这一点来创建一些常量。例如:
public interface Const ants {String ROOT = "/root";int MAX_COUNT = 200;int MIN_COUNT = 100;} |
public interface RandomColor {int red = Math.random() * 255;int green = Math.random() * 255;int blue = Math.random() * 255;}
其中red、green和blue的值会在第一次被访问时建立,然后保持不变。
三、用接口来定义基本数据结构
在设计一套软件系统的初期,我们可以用接口来对一些基本数据元素的特性来进行一些描述,再根据需要进行不同的实现。请大家看看下面这个例子:
public interface User
{int getAge(); String getName(); String getPassword();} public class XMLUser implements User {// 这里用XML技术实现User接口中的方法public int getAge() { ... }public String getName() { ... }public String getPassword() { ... } } public abstract class UserFactory { public static UserFactory getUserFactory() { return new XMLUserFactory(); } public User getUser(String name); public User getAdmin(); public User createUser(String name, String password, int age); public void addUser(User user); public void delUser(User user); } public class XMLUserFactory extends UserFactory {// 这里用XML技术实现的UserFactory的抽象方法} |
在这个例子中,我们定义了一个接口User和一个抽象类UserFactory。然后我们用XML技术实现这两个类。可以看出,我们只需要从用UserFactory的getUserFactory()就可以得到一个UserFactory的实例,而不用去考虑这个实例的具体实现方法。通过UserFactory的这个实例我们还可以直接得到User的实例,也不用去考具体的实现方法。
如果我们决定用JDBC技术来实现User和UserFactory,我们只需要按上面的形式实现JDBCUser和JDBCUserFactory就行了。然后把UserFactory中的getUserFactory方法修改一下就可以改变了它们的实现方法。而我们已经写好的调用UserFactory和User的部分不需要做任何修改。
这是用接口来定义数据结构的一个简单的例子,在实际应用中还有很多灵活的使用方法,大家需要在学习过程中不断的去体会。
四、理解分布式应用的原理
目前有很多软件项目都使用了分布式的技术。Java有多种支持分布式应用的技术,早期用的比较多的有RMI、CORBA等技术,而现在EJB技术更为流行一些。但这些技术不管怎么发展,其实都是以接口为基础的。
以远程方法调用RMI(Remote Method Invocation)为例。在编写RMI应用时,我们需要做两件最基本的事,首先要定义一个接口,这个接口要继承java.rmi.Remote接口,这个接口中应该包含你要从远端调用的方法名。接下来就是写一个类来实现这个接口中的方法。例如:
public interface Product extends java.rmi.Remote
{ String getName() throws java.rmi.RemoteException; } public class ProductImpl implements Product { String name; public ProductImpl(String n) {name = n;} public String getName() throws java.rmi.RemoteException {return name; }} |
现在越来越多的应用使用了EJB这种技术。EJB是从RMI发展而来的一项技术,它比RMI定义得更加完善,可以获得更好的面向对象的特性。但它的规则要比RMI复杂一些。但是不管它多复杂,它同样是使用了接口来定义各种不同的Bean,也同样需要编写相应的实现类来完成具体的功能,最后还要通过Socket来进行通讯。EJB的运作机制本身有一定的复杂性,所以其应用的效率理所当然就会受到一定的影响。因此在选择开发技术时应该根据应用的规模和特点仔细考虑,不一定流行的技术就一定能适应你的应用。如果你很好的掌握了面向对象的设计原则,你就可以自行设计。也许你可以根据自己应用的特点设计出更合适的分布式应用结构。