Java接口与抽象类研究

来源:互联网 发布:水泵选型软件 编辑:程序博客网 时间:2024/06/16 14:52

简介

本文总结了Java抽象类和接口的概念、应用、并对比了两者的区别与联系。

Java抽象类

有时,我们希望通过通用接口来操作一系列有继承关系的类。为此,Java提供了一个叫做抽象方法的机制,这种方法是不完整的,仅有声明而没有方法主体。下面是抽象方法所采用的语法:

abstract void f();
包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。

抽象类不允许实例化;如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中的所有抽象方法提供方法的定义。如果不这样做,那么导出的类仍然为抽象类,且编译器会强制用abstract关键字来限定这个类。

创建抽象类和抽象方法非常有用,因为它们可以使类的抽象性明确起来,并告诉用户和编译器打算怎么来使用它们。抽象类还是很有用的重构工具,因为它们使我们可以很容易的将公共方法沿着继承层次结构向上移动。

Java接口

什么是接口
一个Java接口(Interface)是一些方法特征的集合。一个接口只有方法的特征,而没有方法的实现,因此这些方法在不同的地方被实现时,可以具有完全不同的行为。比如,Java.lang.Runnable是一个Java接口,它的源代码如下:
public interface Runnable() {    public abstract void run();}
Java接口本身没有任何实现,且接口方法只能是抽象的和公开的,Java接口不能有构造函数。Java接口可以定义域,但只能是public、静态和final的域。
接口与类的区别
接口与类最重要的区别是,接口仅仅描述方法的特征,而不给出方法的实现;而类不仅给出方法的特征,而且给出方法的实现。因此,接口把方法的特征和方法的实现分割开来。
接口与抽象类
interface使抽象的概念更向前迈进了一步。abstract关键字允许人们在类中创建一个或多个没有任何定义的方法------提供了接口部分,但是没有提供任何相应的具体实现,这些实现由此类的继承类创建。interface关键字产生一个完全抽象的类,它根本就没有提供任何具体实现。它允许创建者确定方法名、参数列表和返回类型,但是没有任何方法体。接口只提供了形式,未提供任何具体实现。这种约束提供了更大的自由,即使实现接口的类的实现发生了巨大变化,接口客户端仍然可以不受影响。
抽象类描述的是基类与继承类之间的约定,而接口被用来建立类与类之间的协议。
什么是接口继承
在使用接口时,需要指明接口本身,以及实现这个接口的类。一个类实现一个接口,这种关系叫接口继承(Interface Inheritance)。而一个类是另一个类的子类,这种关系叫做实现继承(Implement Inheritance)。接口继承的规则与实现继承的规则不同,一个类最多只能有一个超类,但是可以同时实现几个接口。
接口作用
如前面所述,接口把方法的特征和方法的实现分割开来。通常,实现了一个共同接口的两个类完全不同,但是因为有一组相同的方法,使得看上去不相干的类,可以提供相类似的服务,从而具有相同的接口。这种设计极大的提高了软件的可插入性。
如在Struts 2框架中,所有的动作都可以实现Action接口,该接口对外提供了execute()方法。
/* * Copyright (c) 2002-2006 by OpenSymphony * All rights reserved. */package com.opensymphony.xwork2;/** * All actions may implement this interface, which exposes * the execute() method. However, as of XWork 1.1, this is * not required and is only here to assist users. You are * free to create POJOs that honor the same contract * defined by this interface without actually implementing * the interface. */public interface Action {    /**     * The action execution was successful. Show result     * view to the end user.     */    public static final String SUCCESS = "success";    /**     * The action execution was successful but do not     * show a view. This is useful for actions that are     * handling the view in another fashion like redirect.     */    public static final String NONE = "none";    /**     * The action execution was a failure.     * Show an error view, possibly asking the     * user to retry entering data.     */    public static final String ERROR = "error";    /**     * The action execution require more input     * in order to succeed.     * This result is typically used if a form     * handling action has been executed so as     * to provide defaults for a form. The     * form associated with the handler should be     * shown to the end user.     * <p/>     * This result is also used if the given input     * params are invalid, meaning the user     * should try providing input again.     */    public static final String INPUT = "input";    /**     * The action could not execute, since the     * user most was not logged in. The login view     * should be shown.     */    public static final String LOGIN = "login";    /**     * Where the logic of the action is executed.     *     * @return a string representing the logical result of the execution.     *         See constants in this interface for a list of standard result values.     * @throws Exception thrown if a system level exception occurs.     *                   Application level exceptions should be handled by returning     *                   an error value, such as Action.ERROR.     */    public String execute() throws Exception;}
一个对象要完成一项任务,需要知道其它的对象,并且调用其它对象的方法。这个对象对其它对象的知识叫做关联(Association)。如果一个关联不是针对一个具体类,而是针对一个接口的,那么任何实现这个接口的类都满足要求。这样,就可以动态地将这个关联从一个具体类转换到另一个具体类,而这样做的唯一条件就是它们都实现了这个接口。
同样,一个对象不可避免地需要调用其它对象的方法,这种调用不一定非得是某个具体类,而可以是一个接口。这样以来,任何实现了这个接口的具体类都可以被当前对象调用。而当前对象到底调用的哪个具体类的实例则完全可以动态地决定。同样,举Struts 2中的ActionSupport类的setActionMessage()和getActionMessage()方法,通过将Collection接口作为参数和返回值,可以灵活的支持各种实现了Collection接口的具体类,如ArrayList、HashList的具体类。
/** * Provides a default implementation for the most common actions. * See the documentation for all the interfaces this class implements for more detailed information. */public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {......    public void setActionMessages(Collection messages) {        validationAware.setActionMessages(messages);    }    public Collection getActionMessages() {        return validationAware.getActionMessages();    }......}
因此,接口提供了关联以及方法调用上的可插入性,软件系统的规模越大,生命周期越长,接口的重要性就越大。接口使得软件系统在灵活性和可扩展性、可插入性方面得到保证。

接口与抽象类对比

一个没有抽象方法的抽象类从功能上看与接口相似。然而,需要注意如下区别:

1. 一个类可以实现多个接口,但只能继承最多一个抽象类;interface作为一个极度抽象的类,允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继承变种的特性。

2. 抽象类可以包含具体的方法;接口的所有方法都是抽象的

3. 抽象类可以声明和使用域;接口则不能,但可以声明static和final域作为常量(这些域隐式地是static和final的。在JDK1.5引入enum类型后,通常不建议在接口中声明常量,而是尽量将具有分组类别的常量定义为enum类型)

4. 抽象类中的方法可以是public、protected、private或者默认的package;接口的方法都是public的

5. 抽象类可以定义构造函数;接口则不能

Java设计师应当主要使用Java接口和抽象Java类将软件单位与内部和外部耦合起来。换而言之,应当使用Java接口和抽象类而非具体类进行变量的类型声明、参量的类型声明、方法的返回类型声明以及数据类型的转换等。当然,一个更好的做法是仅仅实现Java接口,而不是使用抽象Java类来做上面的这些工作。在理想的情况下,一个具体Java类应当只实现Java接口和抽象类中声明过的方法,而不应当给出多余的方法。

参考资料

1. Java编程思想(4th)
2. Java与模式
0 0