首页 > 代码库 > Java面向对象----->接口和抽象类

Java面向对象----->接口和抽象类

抽象类和接口()
在实际的项目中,整个项目的代码一般可以分为结构代码和逻辑的代
码。就像建造房屋时,需要首先搭建整个房屋的结构,然后再细化房屋相关的其
它的结构,也像制造汽车时,需要首先制作汽车的框架,然后才是安装配件以及
美化等工作。程序项目的实现也遵循同样的道理。
在项目设计时,一个基本的原则就是——“设计和实现相分离”。也就
是说结构代码和逻辑代码的分离,就像设计汽车时只需要关注汽车的相关参数,
而不必过于关心如何实现这些要求的制作。程序设计时也是首先设计项目的结
构,而不用过多的关系每个逻辑的代码如何进行实现。
前面介绍的流程控制知识,主要解决的是逻辑的代码的编写,而类和
对象的知识,则主要解决结构代码的编写。那么还有一个主要的问题:如何设计
结构代码呢?这就需要使用下面介绍的抽象类和接口的知识了。


抽象类
抽象类(Abstract Class)是指使用 abstract 关键字修饰的类,也就是
在声明一个类时加入了 abstract 关键字。抽象类是一种特殊的类,其它未使用
abstract 关键字修饰的类一般称作实体类。例如:
public abstract class A{
public A(){}
}
抽象方法(Abstract Method)是指使用 abstract 关键字修饰的方法。
抽象方法是一种特殊的方法,其它未使用 abstract 关键字修饰的方法一般称作
实体方法。
public abstract void test();


抽象类和实体类相比,主要有以下两点不同:
l 抽象类不能使用自身的构造方法创建对象(语法不允许)
例如下面的语法是错误的:
A a = new A();
但是抽象类可以声明对象,例如下面的代码是正确的:
A a;
A a1,a2;
只是声明出的对象默认都是 null 的,无法调用其内部的非静态属性和非静态方
法。
说明:抽象类可以使用子类的构造方法创建对象。


l 抽象类内部可以包含任意个(0 个、1 个或多个)抽象方法
抽象类内部可以包含抽象方法,也可以不包含抽象方法,对于包含的个数没有限
制。而实体类内部不能包含抽象方法。
在抽象类内部,可以和实体类一样,包含构造方法、属性和实体方法,
这点和一般的类一样。


抽象方法和实体方法相比,主要有以下几点不同:
l 抽象方法没有方法体
也就是说在声明抽象方法时,不能书写方法体的{},而只能以分号结束方法。下
面是实体方法和抽象方法声明的比较:
抽象方法声明:
public abstract void test(int a);
实体方法声明:
public void test(int a){
方法体
}


l 抽象方法所在的类必须为抽象类
也就是说,如果抽象方法声明在一个类内部,则该类必须为抽象类。(说明:抽
象方法也可以出现在接口内部,这个将在后续进行介绍)。
这样,在继承时,如果继承的类是抽象类,而该抽象类中还包含抽象方法时,则
该子类必须声明成抽象类,否则将出现语法错误。如果子类需要做成实体类的话,
则必须覆盖继承的所有抽象方法。这个是抽象类最核心的语法功能——强制子类
覆盖某些方法。
介绍了这么多抽象类和抽象方法的知识以后,那么抽象类有什么用途
呢?
抽象类的用途主要有两个:
l 严禁直接创建该类的对象
如果一个类内部包含的所有方法都是 static 方法,那么为了避免其它程序员误
用,则可以将该类声明为 abstract,这样其它程序员只能使用类名.方法名调用
对应方法,而不能使用对象名.方法名进行调用。这样的类例如 API 中的 Math

说明:配合 final关键字使用,将必须该类被继承,这样将获得更加完美的效果。
l 强制子类覆盖抽象方法
这样可以使所有的子类在方法声明上保持一致,在逻辑上也必须将方法的功能保
持一致。例如游戏中设计类时,设计了怪物类以及相关的子类,每个怪物类都有
移动方法,但是每种怪物的移动规则又不相同,这样通过使每个怪物类的移动方
法的声明保持一致,方便调用。可以参看前面多态部分的介绍获得更多的关于调
用统一知识。
这是抽象类最主要的用途。就像现实社会中,各种银行网点保持统一的装修风格,
各种快餐店(肯德基、麦当劳等)保持统一的装修甚至风味,这样便于生活中的识
别。通过让存在继承关系的类中功能一样(但是内部实现规则不同)的方法声明成
一样的,方便多态的使用。
那么什么时候在设计时使用抽象类呢?这个问题参看一下抽象类的用途自然就
知道了。关于抽象类的知识先介绍这么多,下面介绍接口的知识,最终将对抽象
类和接口进行一下比较。

 

抽象类和接口()
接口
接口(Interface)是一种复合数据类型。
至此,Java语言的所有数据类型介绍完了,下面进行一个简单的总结。
Java 语言的数据类型分为两大类:基本数据类型和复合数据类型,其中基本数
据类型有 8 种,复合数据类型包括数组、类和接口,由于开发过程中可以根据需
要声明新的复合数据类型,所以复合数据类型的数量有无限个。
接口的概念,现实中使用的也很多,例如大家经常使用的 U 盘,则需
要和计算机上的 USB 接口匹配使用,而且 USB 设备中除了 U 盘以外还有很多,例
如 USB 风扇、USB 数据线、USB 鼠标、USB 键盘等,他们都使用计算机上统一的
USB 接口,这样设备的通用性很强。简化了计算机接口的设计,使计算机不需要
具备鼠标接口、键盘接口等专用的结构。
广义上来说,两个人说不同的方言,互相之间无法听懂另一方表达的
意义,我们也可以称之为双方使用的接口不统一,CPU 无法和主板匹配,我们也
可以称之为接口不统一,例如 AMD 和 Intel 的 CPU 采用不同的针脚结构,甚至同
一厂商不同型号的 CPU 针脚结构也不统一,这样很不方便设备之间的匹配,使用
专业的技术术语叫作兼容性差。
那么什么是接口呢?其实接口就是一套规范。
例如 USB 接口,分为两套规范:公接口和母接口。例如 U 盘、USB 鼠
标上的 USB 接口为公接口,而电脑上的 USB 接口为母接口。规范中只规定公接口
有 4 个通道,那些用来传输数据、那些用来进行供电,母接口规范只规定也有 4
个通道,那些用来传输数据,那些用来进行供电,电压是多少电流多大等。所有
的这些规范都只规定了必须实现那些功能,但是却没有规定如何进行实现。
这种只规定实现什么功能,而不限制如何进行实现的结构,在程序设
计领域中称作“设计和实现相分离”,其中规定实现的功能属于设计部分,而如
何实现功能则是实现部分。这样进行程序项目制作,可以让一部分人专门进行项
目设计,而由另一部分人进行项目实现。这点,很类似汽车的制造,由设计人员
设计汽车,由制造人员进行制造。
这种“设计和实现相分离”的结构将极大的简化程序项目的设计和管
理,使得整个项目的分工更加细致,也就是使程序设计完全独立出来,而在设计
完成以后再进行代码编写。
接口就是一个纯粹用来设计的数据类型,在接口这种数据类型中,只
能书写两类声明的结构:
l 常量数据
所有的常量数据都是 public static 的。如果声明时不书写则系统将自动添加这
两个修饰符。
l 抽象方法
接口中的所有方法都只在逻辑上规定该方法的作用,而不能书写方法体。所有接
口中的方法都是 public abstract 的,如果声明时不书写则系统将自动添加这两
个修饰符。
其中接口中的数据是常数,以后不能改变,而方法只是规定要做什么,
而不去规定如何进行实现。这样接口就很方便设计人员进行设计,而不必过多的
关系对应的方法如何在逻辑上进行实现。
接口声明的语法格式如下:
访问控制符 interface 接口名 [extends 父接口名 1,父接口名 2……]{
常量声明
方法声明
}
和类的声明一样,访问控制符只能使用 public 和默认的。声明时使用
interface 关键字声明接口,接口可以继承其它的接口,使用 extends 关键字进
行继承,多个接口名之间使用逗号进行分隔。和类的集成一样,子接口继承父接
口中所有的常量数据和方法,子接口的对象也是父接口的对象。
注意:和抽象类一样,接口只能声明对象,而不能创建对象。
接口声明的示例代码如下,例如声明一个 USB 接口来代表实际使用中
的 USB 结构:
public interface USB{
/**电压*/
public static final int V = 5;
/**读取数据*/
public abstract byte[] readData();
/**写入数据*/
public abstract void writeData(byte[] data);
}
该接口中规定电压常量为 5V,声明了两个方法,要求实现 USB 时必须
实现这样两个方法,至于如何实现这里不做规定。这样这个数据类型就只是设计
上的说明,而不牵扯具体的实现,这样在项目中使用时则比较通用。
从这点来看,接口类似于现实中使用的各个国家标准,标准中只规定
该类型最终需要达到的标准,而不规定如何实现,各个厂商可以根据自己的产品
工艺实现该要求即可。
在实际的项目中,设计接口需要对于项目的整体有比较深刻的了解和
认识,这样才可以设计出需要的接口结构,关于接口的设计这里不作太深入的论
述 。 如 果 需 要 更 深 刻 的 了 解 设 计 的 结 构 , 可 以 参 阅 OReilly 的
《Designing.Interfaces》一书。
接口设计完成以后,还需要再项目中实现接口规范中对应的要求,一
般声明对应的类来实现接口,实现接口的语法为:
访问控制符 [修饰符] class 类名 [extends 父类名]
implements 父接口名 1,父接口名 2……
实现接口的语法位于类声明中,位于继承声明的后面,使用implements
关键字代表实现,后续是需要实现的接口的名称,一个类可以实现任意多个接口。
实现接口和继承类很类似,声明的类称作接口的子类,接口为该类的
父接口,子类中继承父接口中所有的数据和方法,因为接口中所有的方法都是抽
象方法,所以如果子类中不实现(覆盖)父接口中的方法,则该类必须声明为抽象
类。
例如计算机实现了 USB 接口,则示例代码如下:
public class Computer implements USB{
/**内存容量*/
int memorySize;
public abstract byte[] readData(){
//读数据的逻辑
}
public abstract void writeData(byte[] data){
//写数据的逻辑
}
}
这里,Computer 类实现了前面的 USB 接口,在 Computer 类内部可以
书写和 Computer 类相关的属性、方法和构造方法,这里对于实现接口没有影响,
而因为实现了 USB 接口,则必须覆盖 USB 接口中的 readData 和 writeData 抽象
方法,至于方法内部的代码,则根据逻辑的需要进行实现,从而实现接口中要求
实现的功能。
类似的,也可以使一个数码相机实现 USB 接口,则实现的示例代码为:
public class DigitalCamera implements USB{
/**厂商名称*/
String vendorName;
public abstract byte[] readData(){
//读数据的逻辑
}
public abstract void writeData(byte[] data){
//写数据的逻辑
}
}
在该类中,也可以根据该类的需要实现 USB 接口中规定的功能,至于
如何实现则很可能和 Computer 类不同。
这样,虽然 Computer 类和 DigitalCamera 类自身原来的功能不同,但
是都可以通过实现 USB 接口而实现同样的功能,这样单纯的从是否支持 USB 功能
来看,这两个类的实现是一样的。按照面向对象的术语来说,这被称作屏蔽了类
的类型之间的不同,保证了程序的通用性。
由于实现接口时,不限制实现的接口的数量,则任何一个类都可以实
现任意多个接口,这样就使类的通用性获得了极大的增强,很方便类的对象之间
的匹配。就像现实中 USB 接口规范方便了多种不同设备之间的互联一样。
在语法上,实现了接口的对象可以使用子类的构造方法进行创建,这
样又很适合多态的结构,可以说接口的出现,使多态的特性更容易的进行实现。
在实际项目中,通过使用一定的接口,使得很多类的对象在实现某种
类型的功能时,方法的声明是统一的,便于程序的调用和管理,利于程序项目的
扩展。所以在现在的面向对象编程领域中,存在着另外的一个方向——面向接口
的编程,其实很多 Java 的技术都是这样进行实现的,例如 JDBC 部分。
由于抽象类和接口的功能比较类似,后续将对于抽象类和接口进行一
系列的比较,方便项目设计时的取舍。

 

抽象类和接口()
抽象类和接口的比较
抽象类和接口都是进行面向对象设计时专用的设计结构,在实际进行
项目设计时,经常需要考虑的问题就是——“使用抽象类还是接口”?下面通过
对于抽象类和接口进行简单的比较,熟悉两者之间的区别和联系,从而在实际设
计时使用恰当的结构。
1.什么时候使用抽象类或接口?
当设计中为了规范类中方法声明的结构(即类的行为)时,使用抽象类或接口。也
就是强制子类对外部提供统一的方法声明时,使用抽象类或接口。
2.抽象类和接口的区别(不同点)
a)抽象类是类,而接口是接口。
因为抽象类是一个类,所以类内部可以包含的内容(构造方法、方法和属性等)在
抽象类内部都可以存在,当然抽象类也受到类的单重继承的限制。而接口是接口
类型,所以接口内部只能包含常量属性和抽象方法,但是一个类可以实现多个接
口,所以接口不受类的单重继承的限制。
b)抽象类内部可以包含实体方法,而接口不能
抽象类是一个类,所以在抽象类内部既可以包含抽象方法也可以包含
实体方法,而接口内部的每个方法都必须是抽象方法。
c)抽象类可以继承类,而接口不能
抽象类是一个类,所以在设计时可以使抽象类继承其它的类,在已有
类的基础上进行设计,但是接口不能继承类。
3.抽象类和接口的联系(相同点)
a)抽象类和接口都可以声明对象,但是都只能使用子类的构造方法进行创建。
b)抽象类和接口内部都可以包含抽象方法。
按照 Java 语言的语法,子类在继承抽象类或实现接口时,都必须覆盖
这些抽象方法,否则必须声明为抽象类。
c)抽象类和接口都可以代表一种类型,从而可以统一子类对象的类型,获得良
好的可扩展性。
4.什么时候使用抽象类?
当满足以下的条件时,最好使用抽象类进行设计:
a)子类不继承其它父类
b)子类中存在完全相同的功能实现的方法
c)子类中存在相同的属性
d)设计出的结构需要继承其它类
当需要满足 d 条件时,只能使用抽象类,否则也可以考虑使用接口实现。
5.什么时候使用接口?
当满足以下的条件时,最好使用接口进行设计:
a)子类已经继承了其它父类
b)子类中不存在完全相同的功能实现方法
c)子类中不存在相同的属性
d)设计出的结构不需要继承其它类
当需要满足 a 条件时,只能使用接口,否则也可以考虑使用抽象类实现。
6.抽象类和接口的其它用途
a)禁止创建该类的对象时,可以把该类声明为抽象类。
b)当需要存储大量的常量数据,而这些常量数据将会在项目中的多个类之间使
用时,可以使用接口。
c)当需要统一具有某种功能的类的对象时,可以使用接口。例如 Serializable
口。
当然,只有经过大量的系统设计训练以后,才可以更加深刻的理解抽
象类和接口的区别和联系,从而更加自如的进行选择。
另外,需要说明的是,不是每个项目中都必须使用抽象类或接口的。

Java面向对象----->接口和抽象类