抽象类与接口
抽象类
抽象类的介绍
1. 用abstract关键字来修饰一个类时,这个类就抽象类
格式:访问修饰符 abstract 类名{}
public class Abstract01 {...}
2. 用abstract关键字来修饰一个方法时,这个方法就是抽象方法
格式:访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
//抽象方法
public abstract void run();
3.抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
抽象类的使用细节
- 抽象类不能被实例化
- 抽象类不一定要包含abstract方法。
- 一旦类包含了abstract方法,则这个类必须声明为abstract
- abstract只能修饰类和方法,不能修饰属性以及其他
- 抽象类可以有任意成员,本质还是类,比如:非抽象方法、构造器、静态属性等等
- 抽象方法不能有主体,即不能实现 (不能有{} )
- 如果一个类继承了抽象类,则他必须实现抽象类的所有抽象方法,否则它自己也声明为抽象类
- 抽象类不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的
public class Abstract01 {
//AA aa = new AA(); 1.'AA' 为 abstract;无法实例化 报错
}
//一旦类包含了abstract方法,则这个类必须声明为abstract
abstract class AA{
private int age;
//abstract只能修饰类和方法,不能修饰属性以及其他
//abstract int age; 此处不允许使用修饰符 'abstract' 报错
//抽象方法
public abstract void run();
//抽象方法不能有主体,即不能实现 (不能有{} )
//public abstract void fly(){}; abstract方法不能有主体 报错
//抽象类不一定要包含abstract方法
public void start(){
System.out.println("我不是抽象类");
}
}
//如果一个类继承了抽象类,则他必须实现抽象类的所有抽象方法,否则它自己也声明为抽象类
class BB extends AA{ //类 "BB"必须声明为抽象,或为实现 "AA" 中的抽象方法 "run()"
@Override
public void run() {
System.out.println("我是抽象类AA的子类,我实现了它的抽象方法run");
}
}
static关键字
用于描述类级别的成员,而不是实例级别的。抽象类是设计用来被子类继承的,而static成员是属于类本身而非实例,因此将static关键字用于抽象类的成员会导致矛盾。抽象类的实例化是通过子类完成的,而static成员是与类直接相关的,不依赖于具体的实例。因此,在抽象类中使用static关键字不符合抽象类的设计理念。
final关键字
- 中文意思:最后的、最终的
- final可以修饰类、属性、方法和局部变量
- 当不希望类被继承时,可以用final修饰
- 当不希望父类的某个方法被子类覆盖/重写(override)时,可以使用final关键字修饰 (访问修饰符 final 返回类型 方法名)
- 当不希望类的某个属性的值被修改,可以使用final修饰 (public final double MAX_NUMBER = 1.0)
- 当不希望某个局部变量被修改,可以使用final修饰(final double MIN_NUMBER =0.8)
包装类(Integer,Double等等)String类都是final类
抽象类实践——模板设计模式
实例代码:
// 抽象类定义模板方法
abstract class Template {
// 模板方法定义算法的骨架
public final void templateMethod() {
System.out.println("算法的开始");
// 调用抽象步骤
step1();
step2();
System.out.println("算法结束");
}
// 具体步骤由子类实现
protected abstract void step1();
protected abstract void step2();
}
// 具体子类实现具体步骤
class ConcreteClass extends Template {
@Override
protected void step1() {
System.out.println("ConcreteClass:执行步骤1");
}
@Override
protected void step2() {
System.out.println("ConcreteClass:执行步骤2");
}
}
public class TemplatePatternTutorial {
public static void main(String[] args) {
// 使用具体子类实例化抽象类
Template template = new ConcreteClass();
// 调用模板方法,执行算法
template.templateMethod();
}
}
这个例子中,Template抽象类定义了一个模板方法 templateMethod(),其中包含算法的骨架。具体步骤由抽象方法 step1() 和 step2()定义。ConcreteClass是具体子类,实现了这些具体步骤。在 main 方法中,我们创建了一个具体子类的实例,并调用了模板方法来执行整个算法。
接口
接口的基本介绍
接口就是给出一些没有实现的方法,封装在一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
格式:
interface 接口名{
//属性
//方法(1.抽象方法 2.默认实现方法 3.静态方法)
}
示例代码:
public interface Usb {
int n1 = 100;
//等价于 public static final int a = 100;
//在接口中,抽象方法可以省略abstract关键字
void start();
void stop();
//在JDK8后,可以有默认实现方法,需要使用default关键字修饰
default void ok(){
System.out.println("ok");
}
//在jdk8后,可以有静态方法
static void cry(){
System.out.println("cry");
}
}
类通过implements来实现接口,类必须实现接口的抽象方法
public class Camera implements Usb{
public void start(){
System.out.println("相机开始工作了");
}
public void stop(){
System.out.println("相机停止工作了");
}
}
接口的注意事项
- 接口不能被实例化
- 接口中所有的方法是public方法,接口中的抽象方法,可以不用abstract修饰
- 一个普通类实现接口,就必须将该接口的所有方法都实现
- 抽象类实现接口,可以不用实现接口的方法
- 一个类同时可以实现多个接口
- 接口中的属性,只能是final的,而且是public static final修饰符
- 接口中属性的访问形式:接口名.属性名
- 接口不能继承其他的类,但可以继承多个其他的接口
- 接口的修饰符只能是public 和 默认 ,这点和类的修饰符是一样的
继承与接口的区别
接口和继承解决的问题不同
继承:解决代码的复用性和可维护性
接口:设计,设计好各种规范(方法),让其他类去实现这些方法
接口比继承更灵活,继承是满足 is – a 的关系,而接口只需满足 like – a 的关系
接口在一定程度上实现代码解耦