[toc]
abstract关键字
abstract不可与final关键字同时出现
abstract强制继承和覆写,final禁止继承和覆写
abstract不可与static关键字同时出现
abstract方法无方法体实现,static不可直接调用未实现方法
abstract不可与private关键字同时出现
abstract强制继承和覆写,private类外不可见
abstract不可与native关键字同时出现
构造方法不可声明为abstract
abstract方法由子类实现,与子类构造方法命名冲突
成员属性不可声明为abstract
抽象类
子类继承普通类时可以不覆写某一方法
抽象类必须被子类继承,抽象方法强制子类覆写
抽象类继承抽象类无需全部覆写抽象方法
抽象子类不能有与父类同名抽象方法
普通子类需要实现所有父类抽象方法
抽象类可以继承普通类
抽象类中的成员
抽象类中可以定义普通/静态成员
抽象类中的成员属性任意访问权限
抽象类中的方法
抽象类中可定义构造方法为成员赋值
抽象类中可以定义任意权限普通/静态方法
抽象方法没有方法体且有访问控制权限
抽象方法访问权限不能为private
抽象子类可覆写父抽象类方法
抽象类定义
abstract class AbstractClassName { public abstract void abstractMethod (int a); // 抽象方法 public void simpleMethod (int a) { // 普通方法 this.abstractMethod (a); // 普通方法调用子类实现抽象方法 } private int a; // 普通成员 public AbstractClassName (int a){ // 构造方法 this.a = a; } } public class ClassName extends AbstractClassName { @Override public void abstractMethod (int a) { // 方法实现体 } }
抽象类使用
抽象类无法被直接实例化,需要由子类实例化并向上转型
抽象类中可以没有抽象方法,但不可直接实例化
AbstractClassName className = new ClassName();
className.abstractMethod(3);// 调用子类实现的抽象方法
className.simpleMethod(3); // 调用继承父类的普通方法
抽象类隐藏子类
public abstract class AbstractClassName {
public static AbstractClassName getInstance() {
return new ClassName();
}
}
class ClassName extends AbstractClassName {}
接口
普通类/抽象类只能继承单个普通类/抽象类
普通类和抽象类可同时implements多个接口
接口的目的是定义标准和解耦和
接口不是类,不可继承任何一种类
接口可以同时extends多个接口
接口中一般只包含全局常量、抽象方法
普通子类强制覆写所有父接口/抽象类的所有抽象方法
抽象子类/子接口无需覆写接口中所有抽象方法
接口本身是抽象的,可省去abstract关键字
接口中的成员
接口中的成员属性只能为public static final,必须赋初值
接口中成员可简写为类型 名称 = 初值;
接口中的方法
接口中抽象方法声明为public abstract,无方法体
接口中抽象方法可简写为返回值 方法名 (参数列表);
普通/抽象子类覆写方法名称、参数、返回值与接口相同
普通子类覆写方法访问权限大于等于接口方法
接口中静态方法权限仅为public,有方法体
接口中可定义default默认方法,有方法体
接口没有构造方法
接口方法重载
同一接口中方法可重载
普通子类同时继承不同接口/抽象类情况如下
方法名称 | 参数列表 | 返回类型 | 子类情况 |
---|---|---|---|
相同 | 相同 | 相同 | 共用同一方法 |
相同 | 不同 | 相同 | 方法正确重载 |
相同 | 相同 | 不同 | 无法通过编译 |
子抽象类中的抽象方法不能与父接口抽象方法重名
子接口抽象方法与父接口抽象方法重名共用同一方法
接口定义
public interface ICustomClass { String str = "string"; // 全局常量 void interfaceMethod(); // 抽象方法 } public abstract class AbstractCustomClass { public void abstractMethod(); // 抽象方法 } public CustomClassImpl [extends 父类] implements [接口1,接口2] { @Override public void interfaceMethod(){} // 实现逻辑 @Override public void abstractMethod(){} // 实现逻辑 }
接口使用
接口只能由子类实例化向上转型
ICustomClass cc = new CustomClass();
cc.interfaceMethod();
接口扩充
public interface ICustomClass { void methodA(); void methodB(); // 新扩充方法 } public class CustomClassA implements ICustomClass { @Override public void methodA() {} @Override public void methodB() {} // 实现类扩充 } public class CustomClassB implements ICustomClass { @Override public void methodA() {} @Override public void methodB() {} // 实现类扩充 }
接口增删抽象方法需要修改所有实现子类
后期修改造成大量变动问题解决方法如下
① 接口和子类之间增加抽象类
public interface ICustomClass {
void methodA();
void methodB(); // 新扩充方法
}
public abstract class AbstractCustomClass implements ICustomClass{
@Override
public void methodB() {} // 抽象类实现子类公共方法
}
public class CustomClassA extends AbstractCustomClass implements ICustomClass {
@Override
public void methodA() {
super.methodB(); // 公共方法子实现类调用
}
}
public class CustomClassB extends AbstractCustomClass implements ICustomClass {
@Override
public void methodA() {}
@Override
public void methodB() {} // 非公共方法个性化覆写
}
extends抽象类继承父类覆写公共方法逻辑
implements原接口强制实现所有抽象方法
此设计思想在List接口和子类设计中体现
② [JDK1.8] 接口中可定义普通方法和静态方法
public interface ICustomClass {
public abstract void abstractMethod(); // 抽象方法
public static void staticMethod() {} // 静态方法逻辑
default void plugInMethod() {} // 扩充方法逻辑
}
public class CustomClass extends AbstractCustomClass {
@Override
public void abstractMethod() {
ICustomClass.staticMethod(); // 静态方法
this.plugInMethod(); // 扩充方法
}
}
接口解耦
接口实现类均符合接口标准设计
更改接口实现类时无需改测试类
测试类仅需关注接口标准的使用
强制类型转换
同一个子类实例的不同父类和接口之间可以强制类型转换
转型后只能调用目标类型中定义的方法
public interface ICustomClassA { void iMethodA(); }
public interface ICustomClassB { void iMethodB(); }
public abstract class AbstractCustom { abstract void aMethod(); }
public class Custom extends AbstractCustom
implements ICustomClassA, ICustomClassB {
@Override
public void iMethodA() { System.out.println("iMethodA"); }
@Override
public void iMethodB() { System.out.println("iMethodB"); }
@Override
public void aMethod() { System.out.println("aMethod"); }
}
public class Test{
public static void main(String[] args) {
ICustomClassA iA = new Custom();
ICustomClassB iB = (ICustomClassB) iA;
AbstractCustom aC = (AbstractCustom) iB;
iA.iMethodA();
iB.iMethodB();
aC.aMethod();
}
}
iMethodA
iMethodB
aMethod
接口实例同为Object和接口子类,可用Object接收
Object接收后强转类型可使用目标类型定义方法
ICustomClassA iA = new Custom();
Object obj = iA;
if(obj instanceof ICustomClassB){
ICustomClassB iB = (ICustomClassB) obj;
iB.iMethodB();
}
iMethodB
抽象类与接口对比
相同 | 抽象类 | 接口 |
---|---|---|
作用 | 均强制子类实现abstract方法 | |
实例化 | 均需子类实例化向上转型 | |
静态成员 | public static均可通过类名调用 | |
访问权限 | 均不可被修饰为final |
区别 | 抽象类 | 接口 |
---|---|---|
内容 | 普通/静态成员 普通/静态/抽象/构造方法 构造块/静态块 |
全局常量 静态/默认/抽象方法 |
权限 | 成员非private | 成员均public |
关键字 | abstract不可省略 | abstract可省略 |
父类 | Object | 无父类 |
继承 | 单继承,可继承类和接口 | 多继承,只可继承接口 |
覆写 | 可覆写方法 | 不可覆写方法 |
模板方法设计模式
抽象父类规定方法的调用顺序
子类实现抽象方法的具体逻辑
调度方法设置final禁止重写
public abstract class AbstractCriteria {
public abstract void methodA();
public abstract void methodB();
public abstract void methodC();
public final void execute() {
this.methodA();
this.methodB();
this.methodC();
}
}
class Criteria extends AbstractCriteria {
@Override
public void methodA() {}
@Override
public void methodB() {}
@Override
public void methodC() {}
}
class TestDemo {
public static void main(String[] args) {
new Criteria().execute();
}
}