在面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是并不是所有的类都能用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就应该被定义为抽象类。
抽象类
概述
比如,我们要描述“动物”,它具有年龄、体积,会叫,能跑。但是又缺乏足够的特性(相较于阿猫,阿狗,它们都是动物,却有自己的特性),我们没有唯一的一种能够代表动物的东西(当然,这是相对于猫、狗来说的,在生物学上,动物还是有办法来定义的),这时我们可以用抽象类来描述它。当我们用某个类来具体描述“猫”时,这个类就可以继承“动物”这个抽象类,然后加以具体描述。抽象类的子类在类中必须实现抽象类中的抽象方法,比如说动物类中的跑和叫,在子类中(猫类,狗类)必须实现其是如何跑,怎么叫。抽象方法没有方法体,且用abstract修饰。
下面我们来系统的介绍一下抽象类:
特点
a. 抽象方法和抽象类用关键字abstract表示。
b. 抽象类不能被实例化
c. 有抽象方法的类一定是抽象类(或者接口);抽象类中不一定有抽象方法。
d. 如果一个类继承抽象类,那么这个类要么本身也是抽象类,要么这个类重写父类的所有抽象方法。
用途
强制要求子类必须完成某些功能。
成员特点
A. 成员变量 -- 可以有成员变量,也可以有常量
B. 构造方法 -- 有构造方法,用于子类访问父类之前,对父类数据进行初始化。
C. 成员方法 -- 可以有抽象方法,也可以有关非抽象方法。
i. 抽象方法是为了要求子类做某些事情。
ii. 非抽象方法时为了提高代码复用性,被子类继承。
注意:
不能与final、private、static 共存。
抽象类(abstract class)的定义方式如下:
public abstract class AbstractClass //里面至少有一个抽象方法
{
public int a; //普通数据成员
public abstract void method1(); //抽象方法,抽象类的子类在类中必须实现抽象类中的抽象方法
public abstract void method2();
public void method3(); //非抽象方法
publicvoid method3(){
…… //抽象类中可以赋予非抽象方法方法的默认行为,即方法的具体实现
}
}
接口
定义
是一种特殊的抽象类。比抽象类更抽象,因为它里面的方法都是抽象的。
格式
Class 类名 implements 接口名
{
}
特点
A. 接口不能实例化。
B. 接口中的方法:
a) 要么被子类重写
b) 要么子类也是抽象类。
成员特点
成员变量 -- 接口中只有常量。
因为接口的成员变量有默认修饰符。推荐:永远自己给出修饰符,public static final
构造方法 -- 接口中没有构造方法。
任何类如果没有继承父类,那么这个类就继承Object类
成员方法 -- 接口中的方法都是抽象的。
因为接口中的 成员方法有默认修饰符。推荐:永远自己给出修饰符,public abstract
思想特点:
1. 对外暴露的规则。
2. 程序的功能扩展
3. 降低耦合性
4. 用来多实现。
接口(interface)的定义方式如下:
interface Interface
{
public static final int i; //接口中不能有普通数据成员,只能够有静态的不能被修改的数据成员,static表示全局,final表示不可修改,可以不用static final 修饰,会隐式的声明为static和final,但是建议永远自己给出修饰符public static final
public abstract void method1(); //接口中的方法一定是抽象方法,所以可以不用abstract修饰,但是建议永远自己给出修饰符public abstract
public void method2(); //接口中不能赋予方法的默认行为,即不能有方法的具体实现。(注意,此处及省略了abstract.)
}
class zi implements Interface
{
publicvoid method1()
{
…… //把接口中的抽象方法重写
}
public void method2()
{
…… //注意,是把抽象方法全部重写(接口里的方法全部是抽象方法)
}
}
//另一种情况,子类也是抽象类,此时可以不重写接口中的方法
/*
abstract class zi implements Interface
{
public abstract void method1(); //没有重写
public void method2() //重写了method2()
{
System.out.println("重写了method2()");
}
}
*/
抽象类与接口的对比
|
| 抽象类 | 接口 |
成员特点
| 成员变量 | 变量或常量 | 常量 默认修饰符 public static final |
构造方法 | 有 | 无 | |
成员方法 | 抽象方法或非抽象方法 | 抽象方法 默认修饰符public abstract | |
设计理念 | 理念 | 被继承,定义的是整个继承体系的共性内容 | 被实现,定义的是整个体系的扩展内容 |
体现 | is a | like a |
关系特点
| 类与类 | 继承关系,只能单继承,可以多层继承 |
类与接口 | 实现关系,可以单实现,也可以多实现。还可以继承一个类的同时,实现多个接口。 | |
接口与接口 | 继承关系,可以单继承,也可以多 继承。 |
补充:
进一步理解,关于java中引入抽象类、接口的目的,度娘上有高手的答复如下:
1、从类的层次结构上看,抽象类是在层次的顶端,但在实际的设计当中,一般来说抽象类应当是后面才会出现。为什么?实际上抽象类的获取有点像数学中的提取公因式:ax+bx,x就是抽象类,如果你没有前面的式子,你怎么知道x是不是公因式呢?在这点上,也符合人们认识世界的过程,先具体后抽象。因此在设计过程中如果你得到大量的具体概念并从当中找到其共性时,这个共性的集合就是抽象类应当是没错的。
2、interface从表面上看,和抽象类很相似,但用法完全不同。它的基本功能就是把一些毫不相关的类(概念)集合在一起形成一个新的、可集中操作的“新类”。一个典型的例子就是“司机”。谁可以当司机?谁都可以,只要领取了驾照。所以不管你是学生,白领、蓝领还是老板,只要有驾照就是司机。
interface DriverLicence {
Licence getLicence();
}
class StudentDriver extends Student implements DriverLicence
{
}
class WhtieCollarEmployeeDriver extends WhtieCollarEmployee implements DriverLicence
{
}
class BlueCollarEmployeeDriver extends BlueCollarEmployee implements DriverLicence
{
}
class BossDriver extends Boss implements DriverLicence
{
}
当我定义了“汽车”类后,我就可以指定“司机”了。
class Car {
setDriver(DriverLicence driver);
}
这时候,Car的对象并不关心这个司机到底是干什么的,他们的唯一共同点是领取了驾照(都实现了DriverLicence接口)。这个应当是接口最强大的地方也是抽象类无法比拟的。
小结
抽象类是提取具体类的公因式,而接口是为了将一些不相关的类“杂凑”成一个共同的群体,因而实用性可能更高一点。两者的出现一方面是减少了代码量,提高了效率,另一方面照应前面提到的继承和多态,使得程序符合面向对象的思想特点,对修改关闭,对拓展开放。