这是我参与 8 月更文挑战的第 12 天,活动详情查看: 8月更文挑战
抽象类概述
当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的功能具体实现方式,那么这些方法都有具体的方法体。
但是有的时候,某个父类只是知道子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。比如一个图形类应该有一个求周长的方法,但是不同的图形求周长的算法不一样。那该怎么办呢?
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是方法功能声明相同,但方法功能主体不同。那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
例如:描述讲师的行为:工作。
描述助教的行为:工作。
描述班主任的行为:工作。
讲师、助教、班主任之间有共性,可以进行向上抽取。抽取它们的所属共性类型:员工。由于讲师、助教、班主任都具有工作功能,但是他们具体工作内容却不一样。这时在描述员工时,发现了有些功能不能够具体描述,那么这些不具体的功能,需要在类中标识出来,通过java中的关键字abstract(抽象)来修饰。
方法只有声明没有实现,用abstract来修饰,该方法就是抽象方法。抽象方法必须定义在抽象类中,该类也用abstract修饰。
抽象类 的使用
抽象类的定义:访问修饰符 abstract class 类名 {}
抽象方法的定义:访问修饰符 abstract 返回值类型 方法名(参数列表) ;****
【示例】抽象类&抽象方法的定义
// 抽象类,员工类
abstract class Employee {
// 抽象方法,用abstract修饰,只有声明没有实现
public abstract void work();
}
// 讲师类
class Teacher extends Employee {
@Override
public void work() { // 实现抽象方法
System.out.println("老师讲java课");
}
}
// 助教类
class Assistant extends Employee {
@Override
public void work() { // 实现抽象方法
System.out.println("助教协助同学解决bug");
}
}
抽象类的特点
抽象类的特点:
1、 用abstract修饰的类称之为抽象类。
2、 抽象类不能被实例化,因为抽象方法只有声明,无法用对象调用该方法。
3、 抽象方法可以定义成员变量和静态变量。
4、 抽象类可以有构造方法,方便子类创建对象时给抽象类的属性赋值。
5、 抽象类中可以定义普通方法,也可以定义抽象方法(没有抽象方法也可以)。
6、 抽象类一定是一个父类,需要子类重写父类的抽象方法,然后在实例化使用。
抽象方法的特点:
1、 用abstract修饰的方法称之为抽象方法。
2、 抽象方法只有方法声明,没有方法体。
3、 子类要么实现父类的抽象方法,要么子类也是一个抽象类,否则编译失败。
4、 抽象方法只能存在于抽象类或接口中,不能存在于普通类中。
注意 :abstract关键字不能和private、final、static关键字共存!
接口( interface )
接口的概述
当抽象类中的方法都是抽象方法的时候,该抽象类可以用另外一种形式来定义和表示,那就是接口interface。接口和数组、类、抽象类是同一个层次的概念。
接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。
抽象类还提供某些具体实现,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面向规范的,规定了一批类具有的公共方法规范。
从接口的实现者角度看,接口定义了可以向外部提供的服务。
从接口的调用者角度看,接口定义了实现者能提供那些服务。
接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的系统之间模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。大家在工作以后,做系统时往往就是使用“面向接口”的思想来设计系统。
定义交通工具时,我定义一个抽象类Vehicle, 在定义子类Car、Plane、Train。没有问题。抽象类和子类是一种一般和特殊的关系。
接口呢,他和子类是实现规则的关系。比如:我定义一个接口Runnable,Car实现它就能在地上跑,Train实现也能在地上跑。飞机实现它也能在地上跑。就是说,如果他是交通工具,就一定能跑,一定要实现Runnable。我再定义接口:Fligntable,如果要在天上飞就一定要实现Flightable接口。
接口的定义
定义接口使用的关键字不是class,而是用interface来修饰。
【示例】接口的定义
interface 接口名 [extends 父接口1, 父接口2, …] {
// 常量定义
// 方法定义
}
定义接口所在的仍为.java 文件,虽然声明时使用的为interface 关键字的编译后仍然会产生.class 文件。这点可以让我们将接口看做是一种只包含了功能声明的特殊类。
注意:使用extends可实现接口的多继承!接口不能实例化!
接口的组成:
接口中定义的属性:都属于全局静态常量,默认由public static final 来修饰。
接口中定义的方法:在JDK1.8以前,都属于抽象方法,默认由public abstract来修饰,
在JDK1.8以后,接口中还可以包含普通的静态方法和default修饰的成员方法。
【示例】接口的组成
public interface Flyable {
// 属性:默认为全局静态属性
/*public static final*/ double MAX_HEIGHT = 8000;
// 方法:JDK1.8以前默认为抽象方法
/*public abstract*/ void fly();
// JDK1.8之后还可以包含静态方法和default修饰的成员方法
public static void showInfo1() {}
default void showInfo2() {}
}
注意:接口中不能有构造方法,因为接口中没有需要初始化的成员变量。
接口和抽象类区别
只有弄明白了接口和抽象类的区别,那么你才能知道什么时候该选用接口,什么时候该选用抽象类。
接口是对动作的抽象,抽象类是对根源的抽象。抽象级别(从高到低):接口 > 抽象类 > 普通类。
接口:人可以吃东西,狗也可以吃东西,我们可以把“吃东西”定义成一个接口,然后让这些类去实现它。
抽象类:人有姓名和年龄属性,也有吃饭的行为,狗也有姓名和年龄属性,也有吃饭行为,我们可以把“相同的属性和行为”定义在一个抽象类中,然后让这些类去继承这个抽象类。
相同点:
1、 都是不断向上抽取而来的,都不能被实例化。
2、 都包含抽象方法,但不提供具体的实现。
不同点:
1、 抽象类需要被继承extends,而且只能单继承;
接口需要被实现implements,而且可以多实现。
2、 抽象类中可以定义成员变量也可以定义静态变量;
接口中定义的变量,默认为全局静态常量(public static final来修饰)。
3、 抽象类中可以定义构造方法,方便子类调用并给抽象类中的成员变量赋值;
接口中不能定义构造方法,因为接口中没有成员变量需要初始化!
4、 抽象类中可以定义普通方法,也可定义抽象方法(abstrct);
接口JDK1.8之前,只能定义抽象方法(public abstrct),JDK1.8之后还可以定义静态方法。
5、 抽象类的继承,描述的“is a”关系,用于定义该体系的基本共性内容;
接口的实现,描述的“is like a”关系,用于定义体系之外的额外行为。
面向接口编程
面向接口编程是面向对象编程的一部分。
为什么需要面向接口编程?软件设计中最难处理的就是需求的复杂变化,需求的变化更多的体现在具体实现上。我们的编程如果围绕具体实现来展开就会陷入“复杂变化”的汪洋大海中,软件也就不能最终实现。我们必须围绕某种稳定的东西开展,才能以静制动,实现规范的高质量的项目。
接口就是规范,就是项目中最稳定的东西! 面向接口编程可以让我们把握住真正核心的东西,使实现复杂的多变的需求成为可能。通过面向接口编程,而不是面向实现类编程,可以大大降低程序模块间的耦合性,提高整个系统的可扩展性和和可维护性。