9.2  实现接口

接口的实现完全取决于具体的应用。从这一点讲,实现接口是“面向应用”的编程。利用接口,可以实现间接多重继承。接口本身也具有多重继承性。接口还可以用作参数类型。这一小节用实例讨论这些概念和技术。

9.2.1  完善接口方法

       对接口的完善( implementation ,也称实现)使用关键字 implements 完成。完善接口的类必须遵循接口中规定的方法签名和返回类型要求。如果接口只规定静态常量,则完善它的类无须作任何工作 , ,只是继承了这些静态常量。
1 :以计算圆形物体表面积和体积为例,讨论如何完善在 9.1.3 中编写的 Printable     接口:

 

// 完整程序存在本书配套资源目录 Ch9 名为 CircleShape2.java
public abstract class CircleShape2 extends Shape implements Printable {    
    protected double radius;
    ...
    public void print() {
        System.out.println("radius: " + radius);
    }
   
}

 

CircleShape2 的子类,例如 Circle ,以及 Sphere 等,还可以覆盖完善了的 print() 方法,添加更多具体的打印信息。
2 :以第 8 章计算公司雇员工资为例,把它修改为利用接口来实现多态功能。首先,我们定义如下一个接口:

 

// 这个程序存在本书配套资源目录 Ch9 名为 AccountPrintable.java
//Accounting Printable interface
import java.text. * ;
import java.util. * ;
public interface AccountPrintable{
    void print();
    NumberFormat currencyFormat(Locale locale);
}

 

这个接口规定了继承它的类必须完善 print() 以及 currencyFormat() 方法。而且规定 currencyFormat() 必须具有 Locale 参数,用来规定货币种类,以及返回类型为 NumberFormat 的对象。这为链接调用 format() 方法实现货币格式化提供了可能性。这个接口可以用在任何账务应用程序。

 

// 完整程序存在本书配套资源目录 Ch9 名为 Employee2.java
public abstract class Employee2 implements AccountPrintable {
    ...
    public abstract double earnings();  // 定义抽象方法作为多态接口
    public void print() {               // 完善 print()
        System.out.print("Name: " + name + "\t");
    }
    public NumberFormat currencyFormat(Locale locale) {
                                        // 完善 currencyFormat()
        NumberFormat currency = NumberFormat.getCurrencyInstance(locale);
        return currency;
    }
}

 

子类 Manager2 可以覆盖超类 Employee2 完善的 print() 方法如下:

 

// 完整程序存在本书配套资源目录 Ch9 名为 Manager2.java
public class Manager2 extends Employee2 {
    protected double salary;
    ...
   public double earnings() { return salary; }
                                    //override the method to retrieve salary
       public void print() {    // 覆盖 print()
        super.print();              // 调用超类 print()
        System.out.print("Salary: " + currencyFormat(Locale.US).
        format(earnings()) + "\n"); // 链接调用
    }
}

 

这里,覆盖超类 print() 的目的是加入打印的新内容。即除调用超类 print() 打印姓名外,再调用超类的 currencyFormat() ,以规定的货币格式打印经理的工资。
这个例子中的 SeniorManager 类无须改动。将 RegularWorker 修改如下:

 

// 完整程序存在本书配套资源目录 Ch9 名为 RegularWorker2.java
public class RegularWorker2 extends Employee2 {
   ...
   public void print() {        // 覆盖 print()
       super.print();               // 调用超类 print() 打印姓名
   System.out.println("Salary: " + currencyFormat(Locale.CHINA).
   format(earnings()) + "\n");
   }
}

 

我们有意将普通工人的工资按照人民币结算,表明代码的灵活性。无须对该驱动程序做任何修改,运行后打印如下多态结果:

 

Name: Wang  Salary: $5,800.00
Name: Smith Salary: $7,750.00
Name: Lee   Salary: 3,250.00

 

从以上两个例子可以看出,接口 Printable 可以为所有应用它的类提供一个共享机制。上升到软件设计和结构的角度,这对一个拥有多个大型应用软件开发工程的公司在高层次软件结构设计中,体现标准、互换、管理、维护,以及编程风格方面,是十分有用的。

9.2.2  实现多重继承

Java 允许一个类实现多个接口,如:

 

public class SubClass exends SuperClass implements Interface1 [, Interface2,
, InterfaceN] {
    ...
}

 

其中方括号为可选项。
即子类 SubClass 继承超类 SuperClass ,并完善多个接口。我们称这种代码形式为间接多重继承,因为子类继承了所有 SuperClass 的属性和所有接口中的静态常量和方法签名,但必须提供代码,用来完善各个接口中规定的方法。
1 :间接多重继承的简单演示程序。

 

// 这个程序存在本书配套资源目录 Ch9 名为 CanSwim.java
public interface CanSwim {      // 接口 1
  void swim();
}
interface CanFly {              // 接口 2
  void fly();
}
interface CanWalk {             // 接口 3
  void walk();
}

 

       3 个接口可以被各种有关描述可行动的类,如动物、人、机器、交通工具,等等,进行代码完善。例如:
// 这个程序存在本书配套资源目录 Ch9 名为 SomeOne.java
class abstract Action {     // 超类
  public void DoingList() {
    System.out.println("Here is what I can do: ");
  }
}
// 子类实现间接多重继承
public class SomeOne extends Action implements CanSwim, CanFly, CanWalk {
  public void swim() {
    System.out.println("I can catch fish.");
  }
  public void fly() {
    System.out.println("Sky is my limit.");
  }
  public void walk() {
    System.out.println("I can even run.");
  }
}

 

测试这个间接多重继承的驱动程序如下:

 

// 这个程序存在本书配套资源目录 Ch9 名为 MultipleInheritanceTest.java
public class MultipleInheritanceTest {
    public static void main(String args[]) {
      SomeOne guessWho = new SomeOne();
       guessWho.doingList();
       guessWho.swim();
       guessWho.fly();
       guessWho.walk();
       System.out.println("\nWho am I?");
    }
}

 

这个程序运行后,将打印如下输出信息:

 

Here is what I do:
I can catch fish.
Sky is my limit.
I can even run.

 

Who am I?

 

在本章练习题中,要求读者朋友编写一个类,请求用户输入猜测,并判断这个猜测是否正确的习题。
2 :对计算雇员工资程序做进一步修改,将 earnings() 方法定义在接口中,使之具有更广泛的应用性。例如, earnings() 涉及到账务支付。从这个角度,发票的报销、财务的支出,虽然具体运算操作不同,但都涉及到付款这个功能。可将其定义为如下接口:

 

public interface AccountPayable {
    double payment();
}
这样,任何一个有关财务方面的应用类,都可实现这个接口,提供针对具体应用的代码。修改后的 Employee3 如下:

 

// 完整程序存在本书配套资源目录 Ch9 名为 Employee3.java
public class Employee3 implements AccountPayable, Printable {
    ...
   public double payment(){return 0.0;}     // 完善接口方法
   ...
}

 

子类,如 Manager RegularWorker 等,则用它们各自的运算和操作覆盖超类中完善的这个方法。如:

 

// 完整程序存在本书配套资源目录 Ch9 名为 Manager3.java
public class Manager3 extends Employee3 {
   ...
   public double payment() { return salary; }   //override the method to
   return salary
    ...
   public void print() {                    //override print()
       super.print();
       System.out.print("Salary: " + currencyFormat(Locale.US).
       format(payment()) + "\n");
    }
 }