声明定义抽象类
publicabstractclassCRMSystem{publicabstractClientadd(ClientnewGuy);//添加用户方法publicabstractEventadd(Evente,Clientguy);//重载添加事件、用户方法publicabstractEvent[]todayEvents();//今日事件方法}说明:
- 抽象类有构造器,其访问权限可以声明为
public、protected或default。构造器的作用是在子类实例化时,通过子类的super(...)被调用,用于初始化父类内部的属性。抽象类的构造器不能被直接用于new实例化,子类的普通方法也不能调用父类构造器。 - 接口和抽象类都不能直接实例化(不能
new)。 - 抽象方法所在的类必须是抽象类(从设计意图上讲,接口可以视为一种纯抽象类)。
- 抽象类可以只有抽象方法,没有具体方法。
- 抽象类可以只有具体方法,没有抽象方法。这样设计的唯一目的就是:阻止该类被实例化(例如工具类
Collections)。 - 抽象类的类体内容可以为空。
- 抽象类中的抽象方法的访问权限修饰符可以是
public、protected、default,但是不可以是private。若没有指明访问权限修饰符,默认是default。 - 抽象类中可以声明任意类型的变量(不论是静态的还是非静态的,final的还是非final的,公开的还是私有的)。
- 当一个抽象类实现一个接口时,如果它没有实现接口中的某些抽象方法,那么这些抽象方法会被保留在该抽象类中,作为该抽象类自身的抽象方法,等待其具体的子类去实现。(注意:这里用词是“保留”,而不是“继承”,因为类与接口之间是实现关系)。
abstract不能与final同时修饰同一个类(final阻止继承,abstract强制要求继承,二者矛盾)。abstract不能与private、static、final、native同时修饰同一个方法。- 在抽象类中声明一个与父接口方法签名完全相同的抽象方法,这在概念上称为**“实现”**了接口方法(但未提供实现体)。这属于实现关系,不叫“覆盖重写”,因为接口的抽象方法根本没有方法体可供“覆盖”。
应用场景:
抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。如果某个方法在父类中实现并没有任何意义,而是根据子类的实际需求来进行不同的实现,那么就可以将这个方法在父类中声明为abstract方法,那么这个父类也就成为abstract类了。
声明定义接口
publicinterfaceCRMSystem{Clientadd(ClientnewGuy);Eventadd(Evente,Clientguy);Event[]todayEvents();// 默认方法,用来升级接口publicdefaultvoidmyMethodDefault(){// ...}}说明:
- 接口中声明定义的变量,默认且必须是
public static final,其实就是全局静态常量,所以必须在声明时初始化(即赋值)。 - 接口中定义的常量
子接口(extends)可以访问父接口的常量,并且可以直接通过子接口名引用(例如 ChildInterface.CONSTANT)。但常量在内存中仍然只属于声明它们的父接口,子接口并不“拥有”自己的副本(反射 子接口.class.getDeclaredFields() 不会包含该常量)。
实现类(implements)也可以访问接口常量(通过接口名或直接使用常量名),但同样不拥有这些常量。
日常交流中有时会说“子接口继承了常量”,这是语法层面的通俗说法,严格意义上应说“子接口可以访问父接口的常量”。
接口中声明的抽象方法默认是
public abstract的(可以省略不写),并且不可以是final,也不可以是static。如果是 Java 8,还可以额外包含默认方法和静态方法:
- 默认方法:会被实现子类继承(具体子类可以直接使用,也可以重写它)。
- 静态方法:不会被实现子类继承。接口的静态方法属于接口本身,只能通过“接口名.静态方法”调用,实现类无法访问。
publicdefault返回值类型 方法名(参数列表){方法体}// 默认方法,只能是public,不可加static/finalpublicstatic返回值类型 方法名(参数列表){方法体}// 静态方法,只能是public 或 private,不可加final如果是 Java 9,还可以包含私有方法(纯粹用于接口内部的代码复用):
private返回值类型 方法名(参数列表){方法体}// 私有的普通方法privatestatic返回值类型 方法名(参数列表){方法体}// 私有的静态方法(注:私有方法绝对不被子类继承,也不存在于子类对象的内存中,它们仅存在于接口定义的 bytecode 中,供接口自身的 default/static 方法内部调用。)
不能通过实现子类的对象名称或类名去调用接口的静态方法(会直接编译报错)。静态方法只能通过接口名调用。
接口不可以有静态代码块和构造器。
接口体的内容可以为空(这被称为标记接口,如
Serializable)。