javaSE 基础笔记之抽象类和接口

第七章抽象类和接口

 

 

学习目标:

²        理解和掌握抽象类

²        掌握接口的基本概念

²        掌握多重接口

²        理解解口的基本思想

²        掌握接口作为类型使用

²        理解接口和抽象类的选择

 

 

 

一:抽象类                                                                              

1:抽象类是什么

    有时在开发中,要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类

中实现该行为,取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些

方法。

    这种只给出方法定义而不具体实现的方法被称为抽象方法,抽象方法是没有方法体的,

在代码的表达上就是没有“{}

怎么表示一个方法是抽象的呢?使用abstract修饰符来表达抽象。

abstract 修饰符可以与类和方法一起使用。被修饰的类不能被实例化,被修饰的方法必

须在包含此方法的类的子类中被实现。

抽象类简单地说:使用abstract修饰的类就是抽象类。

示例如下:

public abstract class Test{//抽象类定义

    public abstract void doItByHand();//抽象方法定义

}

2:什么情况下会使用抽象类

    例如,考虑一个Drawing类。该类包含用于各种绘图设备的方法,但这些必须以独立平

台的方法实现。它不可能去访问机器的录像硬件而且还必须是独立于平台的。其意图是绘图

类定义哪种方法应该存在,但实际上,由特殊的从属于平台子类去实现这个行为。

    正如Drawing类这样的类,它声明方法的存在而不是实现,以及带有对已知行为的方法

的实现,这样的类通常被称做抽象类。通过用关键字abstract进行标记声明一个抽象类。被

声明但没有实现的方法(即,这些没有程序体或{} ,也必须标记为抽象。

     

 1     public abstract class Drawing {
 2 
 3             public abstract void drawDot(int x, int y);
 4 
 5             public void drawLine(int x1, int y1, int x2, int y2) {
 6 
 7                  // draw using the drawDot() method repeatedly.
 8 
 9             }
10 
11         }

 

 

 

3:抽象类的使用

    抽象类不能直接使用,必须用子类去实现抽象类,然后使用其子类的实例。然而可以

创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例,也就是可以使用抽

象类来充当形参,实际实现类作为实参,也就是多态的应用。

不能有抽象构造方法或抽象静态方法。

     abstract类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类。

 1 public class MachineDrawing extends Drawing {
 2 
 3    public void drawDot (int machX, int machY) {
 4 
 5             //  画点
 6 
 7    }
 8 
 9 }

Drawing d = new MachineDrawing();
 

4:抽象类和抽象方法

在下列情况下,一个类将成为抽象类:

1 :当一个类的一个或多个方法是抽象方法时;

2 :当类是一个抽象类的子类,并且不能为任何抽象方法提供任何实现细节或方法主

体时;

3 :当一个类实现一个接口,并且不能为任何抽象方法提供实现细节或方法主体时; 

注意:

1 :这里说的是这些情况下一个类将成为抽象类,没有说抽象类一定会有这些情况。

2 :一个典型的错误:抽象类一定包含抽象方法。 但是反过来说“包含抽象方法的类一

定是抽象类”就是正确的。

3 :事实上,抽象类可以是一个完全正常实现的类

 

二:接口的基本概念                                                                       

  接口可以说是 Java程序设计中最重要的概念之一了, “面向接口编程”是面向对象世界

的共识,所以深刻理解并熟练应用接口是每一个学习Java 编程人员的重要任务

 

1:接口概念                                                                                     

     Java 可以创建一种称作接口(interface)的类,在这个类中,所有的成员方法都是抽象的,

也就是说它们都只有定义而没有具体实现,接口是抽象方法和常量值的定义的集合。从本质

上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和

方法的实现。定义接口的语法格式如下:

访问修饰符 修饰符  interface  接口名称  {

  抽象属性集

  抽象方法集

}

示例程序:Runner.java

 1 public interface Runner {
 2 
 3   int ID = 1;
 4 
 5   public void start();
 6 
 7   public void run();
 8 
 9   public void stop();
10 
11 }

 

     目前看来接口和类差不多。确实如此,接口本就是从抽象类中演化而来的,因而除特别

规定,接口享有和类同样的“待遇” 。比如,源程序中可以定义 0~多个类或接口,但最多只

能有一个 public的类或接口,如果有则源文件必须取和 public的类和接口相同的名字。和类

的继承格式一样,接口之间也可以继承,子接口可以继承父接口中的常量和抽象方法并添加

新的抽象方法等。

但接口有其自身的一些特性:

    • 接口中声明的属性默认为,也只能是 public static final的,因而在常量声明时可以省略这些修饰符;
    • 接口中只能定义抽象方法,这些方法默认为 public abstract的、也只能是 public abstract的,因而在声明方法时可以省略这些修饰符;
    • 和继承抽象父类类似,Java 类还可以“实现”接口。

 

      Java 类在继承父类的同时可以同时实现多个接口,也继承了所有接口中的全部成分,

仍然必须重写(实现)全部抽象方法,否则只能声明为抽象类。

类实现多个接口时,您需要做的仅是在关键字“implements”后用逗号分隔接口。总之,

接口就是其它类需要实现的行为模板(以方法的形式表现)

例:接口定义及实现

程序:Person.java 

 1 public class Person implements Runner { 
 2 
 3   public void start() {
 4 
 5     //弯腰、蹬腿、咬牙、瞪眼、 开跑
 6 
 7   }
 8 
 9   public void run() {
10 
11     // 摆动手臂、 维持直线方向
12 
13   }
14 
15   public void stop() {
16 
17     // 减速直至停止、喝水。
18 
19   }
20 
21 }
22 
23  

 

2:为什么使用接口                                                                             

    两个类中的两个类似的功能,调用它们的类动态地决定一种实现, 那它们提供一个抽象

父类,子类分别实现父类所定义的方法。

问题的出现:Java 是一种单继承的语言,一般情况下,哪个具体类可能已经有了一个父

类,解决是给它的父类加父类,或者给它父类的父类加父类,只到移动到类等级结构的最顶

端。这样一来, 对一个具体类的可插入性的设计,就变成了对整个等级结构中所有类的修改。 

接口是可插入性的保证。

    在一个等级结构中的任何一个类都可以实现一个接口, 这个接口会影响到此类的所有子

类,但不会影响到此类的任何父类。此类将不得不实现这个接口所规定的方法,而其子类可

以从此类自动继承这些方法,当然也可以选择置换掉所有的这些方法,或者其中的某一些方

法,这时候,这些子类具有了可插入性(并且可以用这个接口类型装载,传递实现了他的所

有子类)

    我们关心的不是哪一个具体的类,而是这个类是否实现了我们需要的接口。

接口提供了关联以及方法调用上的可插入性,软件系统的规模越大,生命周期越长,接

口使得软件系统的灵活性和可扩展性,可插入性方面得到保证。

 

3:接口的基本作用                                                                                        

    接口把方法的特征和方法的实现分割开来。这种分割体现在接口常常代表一个角色,它

包装与该角色相关的操作和属性,而实现这个接口的类便是扮演这个角色的演员。一个角色

由不同的演员来演,而不同的演员之间除了扮演一个共同的角色之外,并不要求其它的共同

之处。

对于下述情况,接口是有用的:

   1 声明方法,期望一个或更多的类来实现该方法。

   2)揭示一个对象的编程接口,而不揭示类的实际程序体。 (当将类的一个包输送到其

它开发程序中时它是非常有用的。

   3 捕获无关类之间的相似性,而不强迫类关系。

  (4)可以作为参数被传递到在其它对象上调用的方法中

 

4:接口示例                                                                                   

1:接口示例1:接口定义,接口实现类

 

2:接口示例2:一个接口可以有多个不同的实现类

3:接口示例3:一个类可以继承,也可以实现

三:多重接口                                                                                 

1:多重接口的基本概念                                                                 

    一个类只可以继承一个父类(保持有兄弟关系,同属一族) ,但可以实现多个接口,而

不需要在继承树中同属一个族。一个类实现多个接口就被称为多重接口。

    类不可多重继承,因为两个父类的变量或方法可能重复。而接口不会继承变量,即便两

个接口方法定义相同,接口中没有方法实现,类中也只有一个方法实现。

  如下图所示:SeaPlane实现了Flyable Sailer 两个接口,继承了 Airplane

 

 

    接口的多重实现机制从一定程度上弥补了 Java 类单继承的局限,不但多个无关的类可

以实现同一个接口,一个类可以同时实现多个无关的接口。与继承关系类似,接口与其实现

类之间存在多态性。如果说继承父类代表着获得一种“家族身份”的话,实现接口则意味着

取得了某种“资格” 。在 java GUIGraphical User Interface,图形用户界面)事件处理中,

大量使用了接口,届时读者会对此有更深入的了解。

 

2extendsimplements                                                              

注意 extends从句放在 implements 从句之前,这样一个类既具有自己定义的方法,继

承父类方法,同时具有覆盖的接口方法。

 1 class Bird extends Animal implements Flyable{
 2 
 3 //自己定义
 4 
 5    public void buildNest(){}
 6 
 7    public void layEggs(){}
 8 
 9 //继承父类
10 
11    public void eat(){}
12 
13 //覆盖方法
14 
15    public void takeOff(){//加速起飞}
16 
17    public void land(){//减速着陆}
18 
19    public void fly(){//保持引擎运转}
20 
21 }
22 
23  

 

3:接口多继承                                                                    

事实上,Java的接口是可以实现多继承的,类不允许多继承。如下示例:

 1 public  interface Test extends A,B {
 2 
 3   //定义
 4 
 5 }
 6 
 7 interface A{
 8 
 9   //定义
10 
11 }
12 
13 interface B{
14 
15   //定义
16 
17 }

 

 

四:接口的基本思想                                                                          

     接口及相关机制的最基本作用在于:通过接口可以实现不相关类的相同行为,而不需考

虑这些类之间的层次关系。根据接口可以了解对象的交互界面,而不需了解对象所属的类。 

面向对象程序设计讲究“提高内聚,降低耦合” ,那么不同的程序模块怎么相互访问呢,

就是通过接口,也就是接口是各部分对外的统一外观。接口在 Java 程序设计中体现的思想

就是隔离,因为接口只是描述一个统一的行为,所以开发人员在面向接口编程时并不关心具

体的实现。

     由以上讲到的接口的作用和基本思想可以看到,接口在面向对象的 Java 程序设计中占

有举足轻重的地位。事实上在设计阶段最重要的任务之一就是设计出各部分的接口,然后通

过接口的组合,形成程序的基本框架结构。

  具体的接口的在设计和实现中的使用,本书将在第二部分 Java 程序设计和第三部分案

例分析里面,结合具体的例子详细讲述,希望同学们好好体会。

 

五:接口作为类型使用                                                                        

1:接口的使用                                                                                   

  接口的使用与类的使用有些不同。

  在需要使用类的地方,会直接使用 new关键字来构建一个类的实例进行应用:

    ClassA    a    =   new ClassA(); 这是正确的

  但接口不可以这样用,因为接口不能直接使用 new关键字来构建实例。

    InterfaceA   a   = new InterfaceA();  这是错误的

  接口在使用的时候要实例化相应的实现类。

    InterfaceA   a   =   new ImplementsA();    这是正确的

    下面就可以使用a.method()的方式来调用接口的方法了。

2:接口作为类型使用                                                                                         

    接口作为引用类型来使用,任何实现该接口的类的实例都可以存储在该接口类型的变量

中,通过这些变量可以访问类中所实现的接口中的方法,Java 运行时系统会动态地确定应

该使用哪个类中的方法,实际上是调用相应的实现类的方法。

示例如下:

 1 public  class Test {
 2 
 3   public void test1(A a){
 4 
 5     a.doSth();
 6 
 7   }
 8 
 9   public static void main(String[] args) {
10 
11     Test t = new Test();
12 
13    
14 
15     A a = new B();
16 
17     t.test1(a);
18 
19   }
20 
21 }
22 
23 interface A{
24 
25   public int doSth(); 
26 
27 }
28 
29 class B implements A{
30 
31   @Override
32 
33   public int doSth() {
34 
35     System.out.println("now in B");
36 
37    return 123;
38 
39   }
40 
41 }

 

运行结果:now in B

 

大家看到接口可以作为一个类型来使用,把接口作为方法的参数和返回类型。

 

六:接口和抽象类的选择                                                                    

      由于从某种角度讲,接口是一种特殊的抽象类,它们的渊源颇深,有很大的相似之处,

所以在选择使用谁的问题上很容易迷糊。

    很多人有过这样的疑问:为什么有的地方必须使用接口而不是抽象类,而在另一些地方,

又必须使用抽象类而不是接口呢?或者说,在考虑Java类的一般化问题时,很多人会在接口和

抽象类之间犹豫不决,甚至随便选择一种。 

    实际上接口和抽象类的选择不是随心所欲的。 要理解接口和抽象类的选择原则,有两个概

念很重要:对象的行为和对象的实现。如果一个实体可以有多种实现方式,则在设计实体行为的

描述方式时,应当达到这样一个目标:在使用实体的时候,无需详细了解实体行为的实现方式。

也就是说,要把对象的行为和对象的实现分离开来。既然 Java 的接口和抽象类都可以定义不提

供具体实现的方法,在分离对象的行为和对象的实现时, 到底应该使用接口还是使用抽象类呢? 

在接口和抽象类的选择上,必须遵守这样一个原则: 行为模型应该总是通过接口而不是抽象

类定义。所以通常是:

1 :优先选用接口,尽量少用抽象类。

 

练习实践                                                 

程序 1                                                                              

接口与Java 的“多继承”

需求:定义多个接口,并实现多接口继承

目标:

1.  接口的含义;

2.  Java 中多继承的接口实现;

程序:

 1 //: Adventure.java
 2 
 3 package com.useful.java.part3;
 4 
 5 import java.util.*;
 6 
 7 interface CanFight {
 8 
 9          void fight();
10 
11 }
12 
13 interface CanSwim {
14 
15          void swim();
16 
17 }
18 
19 interface CanFly {
20 
21          void fly();
22 
23 }
24 
25 class ActionCharacter {
26 
27          public void fight() {}
28 
29 }
30 
31 class Hero extends ActionCharacter implements CanFight, CanSwim, CanFly {
32 
33          public void swim() {}
34 
35          public void fly() {}
36 
37 }
38 
39 public class Adventure {
40 
41          static void t(CanFight x) { x.fight(); }
42 
43          static void u(CanSwim x) { x.swim(); }
44 
45          static void v(CanFly x) { x.fly(); }
46 
47          static void w(ActionCharacter x) { x.fight(); }
48 
49          public static void main(String[] args) {
50 
51                    Hero i = new Hero();
52 
53                    t(i); // Treat it as a CanFight
54 
55                    u(i); // Treat it as a CanSwim
56 
57                    v(i); // Treat it as a CanFly
58 
59                    w(i); // Treat it as an ActionCharacter
60 
61          }
62 
63 }

 

说明:

1 Java C++不同,不存在多继承,如果非在实现多继承,那只有通过接口,变向实

现;

2 从中可以看到,Hero 将具体类 ActionCharacter 同接口 CanFightCanSwim 以及

CanFly合并起来。 按这种形式合并一个具体类与接口的时候, 具体类必须首先出现,

然后才是接口(否则编译器会报错) 。请注意 fight()的签名在 CanFight 接口与

 

作业                                                     

1:定义一个对象“交通工具” ,并定义接口,说明交通工具可以移动。继承交通工具而产生

汽车、飞机、轮船,并定义类来实现其移动的方法。

2:定义一个类来使用上面的接口

posted @ 2014-03-23 13:28  Jemutse  阅读(171)  评论(0)    收藏  举报