Java在线教程——接口篇

Interfaces 接口

  在软件工程中,由一份“契约”规定来自不同的开发小组的软件之间如何相互作用是非常常见的。每个小组都可以在不知道别的组的代码的前提下独立开发自己的代码。Java中的interface就是这样的一份“契约”。

  举个例子,假设在未来社会有一种智能汽车,它可以在自动运载旅客而不需要人工操作。汽车生产商开发了软件(当然是用Java)来控制这种汽车停止,发动,加速,左转等等。电子导航仪器生产商负责开发接受GPS位置数据和交通状况无线传输的电脑系统,并且应用这些信息来驾驶汽车。

  汽车生产商必须公布工业标准interface,该interface需详细解释哪些methods可以用于控制汽车运动(该标准适用于任何汽车,任何生产商)。导航系统生产商就可以应用这个interface所介绍的各种methods来控制汽车。任何一个工业厂商都不需了解其他厂商是如何实现他们的软件的。事实上,只要大家都严格遵守所公布的interface,每个厂商对其自己的软件都有高度所有权,并且保有随时修改的权利。

  在java中的interface

  在java编程语言里,一个interface是引用类型(reference),它与class相似,因此只能包含常量(constants),方法签名(method signatures)和嵌套类型(nested types)。Interface不得含有方法的具体代码(method body)。 Interface 不可被实例化(instantiated),只能被其它class实现(implemented)或者被其它interface继承。

  定义一个interface与创建一个新类类似:

  1. public interface OperateCar {  
  2. // constant declarations, if any 
  3. // method signatures 
  4. // An enum with values RIGHT, LEFT 
  5.    int turn(Direction direction,  
  6.             double radius,  
  7.             double startSpeed,  
  8.             double endSpeed);  
  9.    int changeLanes(Direction direction,  
  10.                    double startSpeed,  
  11.                    double endSpeed);  
  12.    int signalTurn(Direction direction,  
  13.                   boolean signalOn);  
  14.    int getRadarFront(double distanceToCar,  
  15.                      double speedOfCar);  
  16.    int getRadarRear(double distanceToCar,  
  17.                     double speedOfCar);  
  18.          ……  
  19.    // more method signatures 
  20. }

  如想使用上面这个interface,你需要写一个class来实现它。当一个可被实例化的class实现某个接口时,它需要提供所有该interface所声明的所有方法(methods)的具体代码。

  在上面的自动化汽车的例子中,汽车生产商即是接口实现者。由雪佛兰公司的实现方法当然不同于本田公司的方法,但是它们都遵循同一个接口。 导航系统生产商是这个接口的使用者,他们的系统将根据汽车方位的GPS数据,数字化地图和交通情况来驾驶汽车。因此,这个导航系统将会涉及以下的方法(methods): 转弯,切道,刹车,加速等等。

  API 接口

  自动化汽车的例子展示了interface在工业标准应用程序接口(API, Application Programming Interface)中的应用. 在商业软件中,API也很常见。 通常来说,一个公司发售的软件包中会含有其他公司希望应用在自己的产品中的复杂方法(methods)。比如一个包含了数字图形处理方法的软件包就可以出售给开发终端客户图像软件的公司。购买后,该公司就可以应用interface所定义的方法。当图像处理公司向所有客户公开它的API的同时,这些API的实现方法是高度保密的。事实上,只要保留住原始的interface不被改变,这些API的实现方法很可能在将来被重写。

  Interfaces 和多重继承

  在java编程语言里,interface还有另外一个重要作用。 尽管Interface是与类一起使用的,但它并不是类的层次结构的一部分。java编程语言不支持多重继承,但是interface提供了替代方案。

  在java中,一个类只能继承于单一的类,但是它可以实现多个接口。因此,对象可以有多重类型:属于它自身类的类型,和属于它所继承的所有接口的类型。这意味着,如果声明一个变量是某个接口类型,这个变量可以指代任何实现该接口的类的实例。这部分会在“使用接口类型”中详细讨论。

 定义一个interface

  一个接口的定义是由 修饰词(modifiers),关键词 interface, 接口名称,由逗号分隔开的父接口(parent interfaces),和接口实体(interface body)。

  例子如下:

  1. public interface GroupedInterface extends Interface1, Interface2, Interface3 {  
  2. // constant declarations  
  3. // base of natural logarithms  
  4.     double E = 2.718282;  
  5. // method signatures   
  6.     void doSomething (int i, double x);  
  7.     int doSomethingElse(String s);  
  8. }

  Public规定了这个接口可以被任何包中的任何类所使用。如果你声明这个接口是public的,它只能被同一个包里的类所使用。

  一个接口可以继承其它接口,就像一个类能后继承其它类一样。但是类只能继承一个父类,而接口却可以继承任何数目的接口。

  接口实体(interface body)

  接口实体中含有它所包含的所有方法的声明。每个声明都以引号为结束,因为接口不用实现它所声明的方法。接口中所有的方法都默认是public的,因此修饰词public可以被省略。

  接口还可以声明常量。同样的,常量的修饰词public, static和final可以被省略。

  接口的实现

  为了声明某个类实现了某个接口,你需要在类的声明中使用implements。你的类可以实现多个接口,所以implements关键词后面可以跟随多个由逗号分隔的接口名称。为了方便,implements关键词多跟在extends关键词的后面。

  一个接口实例—Relatable

  Relatable是一个用来比较两个对象大小的接口。

  1. public interface Relatable {  
  2.     // this (object calling isLargerThan)  
  3.     // and other must be instances of   
  4.     // the same class returns 1, 0, -1   
  5.     // if this is greater // than, equal   
  6.     // to, or less than other  
  7.     public int isLargerThan(Relatable other);  
  8. }

  如果你想比较两个相似的对象的大小,不管该对象属于什么类,这个类需要实现Relatable接口。

  只要有办法可以比较对象的相对大小,任何类都可以实现Relatable接口。对字符串来说,可以比较字符数;对书来说,可以比较页数;对学生来说,可以比较体重。对平面几何对象来说,比较面积是很好的选择;对三维对象来说,就需要比较体积了。所有以上的类都能实现int isLargerThan()方法。

  如果你知道某个类实现了Relatable接口,你可以比较从这个类实例化的对象了。

  Relatable接口的实现

  下面是一个三角形类,它实现了Relatable接口。

  1. public class RectanglePlus  
  2.     implements Relatable {  
  3.     public int width = 0;  
  4.     public int height = 0;  
  5.     public Point origin;  
  6.     // four constructors  
  7.     public RectanglePlus() {  
  8.         origin = new Point(0, 0);  
  9.     }  
  10.     public RectanglePlus(Point p) {  
  11.         origin = p;  
  12.     }  
  13.     public RectanglePlus(int w, int h) {  
  14.         origin = new Point(0, 0);  
  15.         width = w;  
  16.         height = h;  
  17.     }  
  18.     public RectanglePlus(Point p, int w, int h) {  
  19.         origin = p;  
  20.         width = w;  
  21.         height = h;  
  22.     }  
  23.     // a method for moving the rectangle  
  24.     public void move(int x, int y) {  
  25.         origin.x = x;  
  26.         origin.y = y;  
  27.     }  
  28.     // a method for computing  
  29.     // the area of the rectangle  
  30.     public int getArea() {  
  31.         return width * height;  
  32.     }  
  33.     // a method required to implement  
  34.     // the Relatable interface  
  35.     public int isLargerThan(Relatable other) {  
  36.         RectanglePlus otherRect   
  37.             = (RectanglePlus)other;  
  38.         if (this.getArea() < otherRect.getArea())  
  39.             return -1;  
  40.         else if (this.getArea() > otherRect.getArea())  
  41.             return 1;  
  42.         else 
  43.             return 0;  
  44.     }  
  45. }

使用接口类型

  在你定义一个新的接口时,你其实在定义一个新的引用类型。在你能使用数据类型名称的地方,都可以使用接口名称。如果你定义了一个类型为接口的引用变量,该变量能指向的对象所在的类必须实现了该接口。

  下例是一个在一对对象中返回较大对象的方法:

  1. public Object findLargest(Object object1, Object object2) {  
  2.    Relatable obj1 = (Relatable)object1;  
  3.    Relatable obj2 = (Relatable)object2;  
  4.    if ((obj1).isLargerThan(obj2) > 0)  
  5.       return object1;  
  6.    else 
  7.       return object2;  
  8. }

  通过把数据类型object1转换成Relatable,对象obj1可以调用isLargerThan方法。

  同理,只要是实现了Relatable的类,也可以使用下面的方法。

  1. public Object findSmallest(Object object1, Object object2) {  
  2.    Relatable obj1 = (Relatable)object1;  
  3.    Relatable obj2 = (Relatable)object2;  
  4.    if ((obj1).isLargerThan(obj2) < 0)  
  5.       return object1;  
  6.    else 
  7.       return object2;  
  8. }  
  9. public boolean isEqual(Object object1, Object object2) {  
  10.    Relatable obj1 = (Relatable)object1;  
  11.    Relatable obj2 = (Relatable)object2;  
  12.    if ( (obj1).isLargerThan(obj2) == 0)  
  13.       return true;  
  14.    else 
  15.       return false;  
  16. }

  这些方法适用于任何“Relatable”的类,而无关它们的继承关系。实现了Relatable的类,它们既属于自身(或者父类)的类型,也属于Relatable类型。这使得它们具有了多重继承的优点,因为它们可以同时具备父类和接口的行为。

  重写接口

  假设你开发了一个接口名为DoIt:

  1. public interface DoIt {  
  2.    void doSomething(int i, double x);  
  3.    int doSomethingElse(String s);  
  4. }

  然后,你想加入一个新的方法在这个接口里,因此代码变成:

  1. public interface DoIt {  
  2.    void doSomething(int i, double x);  
  3.    int doSomethingElse(String s);  
  4.    boolean didItWork(int i, double x, String s);  
  5. }

  如果你这么修改了,所有实现了旧的DoIt接口的类都会出错,因为它们不再正确的实现这个接口。所有使用这个接口的程序员会严重抗议你的修改。

  你需要预估你的接口用户的需求,并从开始就完善的设计好这个接口。但是这常常是无法做到的。另一个解决方法就是再写一个接口。例如,你可以写一个DoItPlus的接口继承原有的接口。

  1. public interface DoItPlus extends DoIt {  
  2.    boolean didItWork(int i, double x, String s);  
  3. }

  现在你的用户可以选择继续使用旧接口DoIt,或是升级的新接口DoItPlus。

  总结

  接口就是两个对象间的沟通协议。

  一个接口的声明包含一些方法的签名(signatures),但不需要实现它们;也可能含有一些常量。

  实现某接口的类必须实现该接口所声明的所有的方法。

  在任何使用类型名称的地方都可以使用接口的名字。

====================================分割线================================

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-09-13 04:24:58

Java在线教程——接口篇的相关文章

Java 集合教程

这些Java集合API 以一组类和接口提供给开发者,这样做容易处理object集合,除了它们的size能动态改变之外,感觉collection的工作原理有点像Array,并且它们拥有比Array更多的该机特性 相比于你自己去写一个集合类,不如用Java提供这些立即可以使用的集合类,这个教程将关注于Java集合,并且Java6中有很多特殊的Java集合. 这篇教程的目的是给你一个Java集合类的概述,因此不会挨个讨论每一个Java集合类的细节,这个概述会帮助你在阅读Java Doc 时会更轻松.

Java语言的接口与类型安全

安全 接口是实现构件可插入性的关键,可插入构件的关键在于存在一个公用的接口,以及每个构件实现了这个接口. 什么是接口? Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 接口的两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构:二,一个类所具有的方法的特征集合,是一种逻辑上的抽象.前者叫做"Java接口",后者叫做"接口&qu

漫谈Java语言的接口与类型安全

安全 接口是实现构件可插入性的关键,可插入构件的关键在于存在一个公用的接口,以及每个构件实现了这个接口. 什么是接口? Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 接口的两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构:二,一个类所具有的方法的特征集合,是一种逻辑上的抽象.前者叫做"Java接口",后者叫做"接口&qu

JAVA提高教程(14)-认识Map之LinkedHashMap

Java基础及提高教程目录 Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序.此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表.此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序).注意,如果在映射中重新插入 键,则插入顺序不受影响.(如果在调用 m.put(k, v) 前 m.containsKey(k) 返回了 true,则调用时会将键 k 重新插入到映射 m 中.) 此实现可以让客户避免未指定的.由 HashMap(及

JAVA提高教程(13)-认识Map之Hashtable

这个类,在使用上和HashMap的区别不大,其方法都是同步的(Synchronized). 1.package collection.lession13; 2. 3.import java.util.Hashtable; 4. 5./** 6. * 老紫竹JAVA提高教程(13)-认识Map之Hashtable<br> 7. * 这个类继承自一个已经过期不推荐使用的Dictionary类<br> 8. * 目前均推荐实现Map接口<br> 9. * 10. * 11.

JAVA提高教程(12)-认识Map之HashMap

Map里面使用率最多的,应该是HashMap吧,我们先来看看这个 1.package collection.lession12; 2. 3.import java.util.HashMap; 4.import java.util.Iterator; 5.import java.util.Map; 6. 7./** 8. * 老紫竹JAVA提高教程(12)-认识Map之HashMap<br> 9. * 基于哈希表的 Map 接口的实现.<br> 10. * 一个映射不能包含重复的键:

JAVA提高教程(10)-认识List列表之Stack

不多说,我们直接看源代码 1.package collection.lession10; 2. 3.import java.util.Arrays; 4.import java.util.List; 5.import java.util.Stack; 6. 7./** 8. * 老紫竹JAVA提高教程(10)-认识List列表之Stack<br> 9. * 实现了LIFO的对象堆栈,<br> 10. * 类本身继承自Vector,扩展了一些方法<br> 11. * &l

JAVA提高教程(9)-认识List列表之LinkedList

LinkedList提供了将链接列表用作堆栈.队列或双端队列的方法,这里不再重复介绍 List的标准操作,只给出其独特方法的使用. 请注意其已经实现的接口 Serializable, Cloneable, Iterable<E>, Collection<E>, Deque<E>, List<E>, Queue<E> 1.package collection.lession9; 2. 3.import java.util.Arrays; 4.imp

JAVA提高教程(1)-认识Set集合

集合的基本介绍,全在代码里了.不同的实现,细节不同,使用时稍微注意点就行了 .幸好我们常用的就那么几个. package collection.lession1; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; import java.util.TreeSet; /** * 老紫竹