一天一个知识点——抽象类和接口的共同点和区别?Java&&Python具体实现?

134 阅读4分钟

抽象类

概念

抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类(abstract class)。

抽象方法

一种特殊的方法,它只有声明,没有具体的实现。抽象方法的访问限制必须是public或者protected,不能使用private修饰,因为抽象方法必须被子类继承且重写。此外,构造方法以及类方法不能被声明为抽象方法。在Java中,它使用关键字abstract声明。

public abstract void function();

在Python中,它使用装饰器的方式实现,由@abstractmethod 声明。

@abstractmethod
def function():
    pass

抽象类的特征

  • 不能使用抽象类创建具体的对象,即抽象类不能实例化,只有抽象类的非抽象子类可以创建对象;
  • 抽象类可以包含抽象方法,也可以包含具体方法;
  • 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为抽象类。
    注:
  1. 包含抽象方法的类一定是抽象类,但抽象类不一定包含抽象方法。
  2. 包含抽象方法或者由abstract class关键字声明的类都是抽象类(Java语言中)。

实现

使用Java实现抽象类

在Java中,抽象类使用abstract class关键字来实现。例如,类Bird和类Duck继承自抽象类AbstractAnimal,必须要实现抽象类中的抽象方法,代码如下。

abstract class AbstractAnimal{
    public abstract void calls();
}

class Bird extends AbstractAnimal{
    public void calls(){
        System.out.println("喳喳");
    }
}

class Duck extends AbstractAnimal{
    public void calls(){
        System.out.println("嘎嘎");
    }
}

public class AbstractClassExample {
    public static void main(String[] args){
        Duck duck = new Duck();
        Bird bird = new Bird();
        duck.calls();
        bird.calls();
    }
}

使用Python实现抽象类

在Python中,没有明确的抽象类,但是提供了一个模块abc来创建抽象基类。具体的,可以通过继承abc.ABC来创建,也可以通过将类的metaclass指定为ABCMeta来实现。

from abc import ABC,ABCMeta,abstractmethod

class AbstractAnimal(ABC):

    # 声明calls()为抽象方法
    @abstractmethod
    def calls(self):
        pass

class Bird(AbstractAnimal):
    def calls(self):
        print("喳喳")

class Duck(AbstractAnimal):
    def calls(self):
        print("嘎嘎")

bird = Bird()
duck = Duck()
bird.calls()
duck.calls()

接口

概念

接口

在面向对象编程中,接口是一种抽象类型,是抽象方法的集合,通过接口可以规定程序要做什么,但在接口中不具体实现。

接口的特征

  • 接口不能被实例化,只有实现接口的非抽象类能创建实例对象。
  • 接口中的每一个方法都会被隐式的指定为public abstract。
  • 接口中的所有变量都会被隐式的指定为public static final。
  • 接口中不含有构造方法。
  • 接口中的抽象方法不能包含有具体实现,需要由实现其的非抽象类实现。
  • JDK1.8之前,接口不能包含具体方法,JDK1.8之后,接口允许包含具体方法,用关键字default修饰;JDK1.8之前,接口不能包含静态方法,JDK1.8之后,接口允许包含静态方法。

实现

使用Java实现接口

在Java中,接口的创建和类相似,但由关键字interface来声明。接口更关注行为的约束,例如,类Bird和类Airplane都拥有“飞”这个行为,因此可以定义一个接口fly来抽象“飞”这个行为。

interface fly{
    // 默认方法
    default void defaultFun(){
        System.out.println("接口中的默认方法!");
    }
    // 静态方法
    static void staticFun(){
        System.out.println("接口中的静态方法!");
    }
    // 抽象方法
    abstract void flyfun();
}

class LittleBird implements fly{
    public void flyfun(){
        System.out.println("小鸟迎风飞翔!");
    }
}

class AirPlane implements fly{
    public void flyfun(){
        System.out.println("飞机飞行!");
    }
}


public class InterfaceExample {
    public static void main(String[] args){
        LittleBird littleBird = new LittleBird();
        AirPlane airPlane = new AirPlane();
        littleBird.flyfun();
        airPlane.flyfun();
    }
}

使用Python实现接口

在Python中,接口只是一个概念,没有明确的实现,一般使用class以及abc模块来实现接口。所以在Python中,接口更为灵活。

from abc import ABC,abstractmethod

class fly(ABC):

    @staticmethod
    def staticMethod():
        print("接口中的静态方法!")
    
    @abstractmethod
    def flyfun(self):
        pass

class LittleBird(fly):
    def flyfun(self):
        print("小鸟迎风飞翔!")

class AirPlane(fly):
    def flyfun(self):
        print("飞机在高空飞行!")

fly.staticMethod()
littleBird = LittleBird()
airPlane = AirPlane()
littleBird.flyfun()
airPlane.flyfun() 

抽象类和接口的共同点和区别

共同点

  • 都是一种抽象类型,都不可以被实例化;
  • 都可以包含抽象方法;
  • JDK1.8之后,接口和抽象类都允许包含具体的方法实现;
  • JDK1.8之后,接口和抽象类都允许包含静态方法;

区别

  • 抽象类是对类的抽象,而接口是对行为的抽象,即抽象类关注的是“is-a”,而接口关注的是“has-a”。
  • 抽象类只支持单继承,接口支持多继承;
  • 抽象类中的变量可以有多种类型的,而接口中的变量只能是public static final类型的;
  • 抽象类中可以有静态代码块和构造方法,而接口中不可以有静态代码块和构造方法。

注: Python的类支持多继承,因此,Python中的抽象类和接口都支持多继承。