一、抽象类和接口选择的 “陷阱”
接口和抽象类
在面向对象中,所有的对象都可以抽象为一个类,类还可以进一步抽取类的共同点变成一个抽象类,也就是说并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类,抽象类是用来描述类的,抽象类使用 abstract
关键字来描述。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。一个抽象类中,可以有 0 个或多个抽象方法,以及 0 个或多个具体方法。
接口在 Java 中是一个抽象类型,是抽象方法
的集合,接口通常以 interface
关键字来声明。一个类通过实现接口的方式,从而获取接口中定义的方法。
需要注意的是接口并不是类,类使用 class 关键字描述,接口使用 interface 关键字描述。编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法,接口则包含类要实现的方法。
接口和抽象类的区别
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及构造代码块,而抽象类可以。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
- 接口中不能有构造方法,抽象类可以,抽象类也可以有main方法,同时可以运行它。
- 一个类可以实现多个接口,但是只能继承一个抽象类
接口和抽象类的设计
在设计一个类时如何选择 抽象类 和 接口?
设计实现一个 GigaFactory 类, 对 GigaFactory 的拆分既不能全部是抽象类,也不能全部是抽象接口,比如产能如果定义在接口里面就是一个常量,每个 GigaFactory 工厂的产能是不同的,这样就失去了每个对象的状态信息。
那可以都定义为抽象类吗?
也不能将功能都拆分为抽象类,会导致代码难以维护,这是从代码的灵活性和复杂性考虑的。从语言特性来考虑也不合适,类是对事物的客观抽象,并不是所有的类都具有相同的行为。
可以将共同的属性使用抽象类来表达,比如状态等,而将特有的行为使用接口定义,每个不同的类实现特定的接口。
新建 Maven 项目 abstract-interface-traps,增加 entity 包,定义一个 Factory 抽象类
/** * 每个 Factory 最基本的属性 */ public abstract class Factory { protected String address; protected Integer productivity; } 复制代码
定义生产整车业务的接口类 Vehicle
/** * 整车业务生产,Model 3、Y、X 等 */ public interface Vehicle { void produceCars(); } 复制代码
定义生产配件的接口类
/** * 配件业务生产,电机等 */ public interface Autoparts { void makeParts(); } 复制代码
定义生产太阳能业务的接口类 Energy
/** * 太阳能业务 */ public interface Energy { void produceSolarPanels(); } 复制代码
定义一个上海超级工厂类,继承 Factory 类,实现整车业务接口类 Vehicle
public class ShanghaiGigaFactory extends Factory implements Vehicle{ protected String address = "Shanghai"; protected Integer productivity = 500000; @Override public void produceCars() { } }